fast_mblock reclaimed object pool

pull/5/head
yuqing 2015-11-03 18:13:51 +08:00
parent 8f26a0a354
commit f734884700
3 changed files with 308 additions and 30 deletions

View File

@ -1,11 +1,12 @@
Version 1.23 2015-11-02 Version 1.23 2015-11-03
* sched_thread.c: task can execute in a new thread * sched_thread.c: task can execute in a new thread
* sched_thread.c: support delay tasks * sched_thread.c: support delay tasks
* add function get_current_time_us and get_current_time_ms * add function get_current_time_us and get_current_time_ms
* mblock add stat function * mblock add stat function
* add function get_sys_total_mem_size, ONLY support Linux and FreeBSD * add function get_sys_total_mem_size, ONLY support Linux and FreeBSD
* delay task can execute in a new thread * delay task can execute in a new thread
* fast_mblock reclaimed object pool
Version 1.22 2015-10-10 Version 1.22 2015-10-10
* export php function: fastcommon_get_first_local_ip * export php function: fastcommon_get_first_local_ip

View File

@ -103,11 +103,13 @@ static void delete_from_mblock_list(struct fast_mblock_man *mblock)
strcpy(pStat->name, current->info.name); \ strcpy(pStat->name, current->info.name); \
pStat->element_size = current->info.element_size; \ pStat->element_size = current->info.element_size; \
} \ } \
pStat->total_count += current->info.total_count; \ pStat->element_total_count += current->info.element_total_count; \
pStat->used_count += current->info.used_count; \ pStat->element_used_count += current->info.element_used_count; \
pStat->trunk_total_count += current->info.trunk_total_count; \
pStat->trunk_used_count += current->info.trunk_used_count; \
pStat->instance_count += current->info.instance_count; \ pStat->instance_count += current->info.instance_count; \
/* logInfo("name: %s, element_size: %d, total_count: %d, used_count: %d", */ \ /* logInfo("name: %s, element_size: %d, total_count: %d, used_count: %d", */ \
/* pStat->name, pStat->element_size, pStat->total_count, pStat->used_count); */\ /* pStat->name, pStat->element_size, pStat->element_total_count, pStat->element_used_count); */\
} while (0) } while (0)
int fast_mblock_manager_stat(struct fast_mblock_info *stats, int fast_mblock_manager_stat(struct fast_mblock_info *stats,
@ -209,19 +211,22 @@ int fast_mblock_manager_stat_print()
alloc_mem = 0; alloc_mem = 0;
used_mem = 0; used_mem = 0;
logInfo("%32s %12s %16s %12s %12s %12s", "name", "element_size", logInfo("%32s %12s %16s %10s %10s %14s %12s %12s", "name", "element_size",
"instance_count", "alloc_count", "used_count", "used_ratio"); "instance_count", "trunc_alloc", "trunk_used",
"element_alloc", "element_used", "used_ratio");
stat_end = stats + count; stat_end = stats + count;
for (pStat=stats; pStat<stat_end; pStat++) for (pStat=stats; pStat<stat_end; pStat++)
{ {
block_size = GET_BLOCK_SIZE(*pStat); block_size = GET_BLOCK_SIZE(*pStat);
alloc_mem += block_size * pStat->total_count; alloc_mem += block_size * pStat->element_total_count;
used_mem += block_size * pStat->used_count; used_mem += block_size * pStat->element_used_count;
logInfo("%32s %12d %16d %12d %12d %11.2f%%", pStat->name, logInfo("%32s %12d %16d %10d %10d %14d %12d %11.2f%%", pStat->name,
pStat->element_size, pStat->instance_count, pStat->element_size, pStat->instance_count,
pStat->total_count, pStat->used_count, pStat->trunk_total_count, pStat->trunk_used_count,
pStat->total_count > 0 ? 100.00 * (double)pStat->used_count / pStat->element_total_count, pStat->element_used_count,
(double)pStat->total_count : 0.00); pStat->element_total_count > 0 ? 100.00 * (double)
pStat->element_used_count / (double)
pStat->element_total_count : 0.00);
} }
if (alloc_mem < 1024) if (alloc_mem < 1024)
@ -296,12 +301,14 @@ int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
} }
mblock->alloc_init_func = init_func; mblock->alloc_init_func = init_func;
mblock->malloc_chain_head = NULL; INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->free_chain_head = NULL; mblock->free_chain_head = NULL;
mblock->delay_free_chain.head = NULL; mblock->delay_free_chain.head = NULL;
mblock->delay_free_chain.tail = NULL; mblock->delay_free_chain.tail = NULL;
mblock->info.total_count = 0; mblock->info.element_total_count = 0;
mblock->info.used_count = 0; mblock->info.element_used_count = 0;
mblock->info.instance_count = 1; mblock->info.instance_count = 1;
mblock->need_lock = need_lock; mblock->need_lock = need_lock;
@ -361,6 +368,7 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
return result; return result;
} }
} }
pNode->offset = (int)(p - pNew);
pNode->next = (struct fast_mblock_node *)(p + block_size); pNode->next = (struct fast_mblock_node *)(p + block_size);
} }
@ -373,38 +381,88 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
return result; return result;
} }
} }
((struct fast_mblock_node *)pLast)->offset = (int)(pLast - pNew);
((struct fast_mblock_node *)pLast)->next = NULL; ((struct fast_mblock_node *)pLast)->next = NULL;
mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart; mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart;
pMallocNode->next = mblock->malloc_chain_head; pMallocNode->ref_count = 0;
mblock->malloc_chain_head = pMallocNode; pMallocNode->prev = mblock->trunks.head.prev;
mblock->info.total_count += mblock->alloc_elements_once; pMallocNode->next = &mblock->trunks.head;
mblock->trunks.head.prev->next = pMallocNode;
mblock->trunks.head.prev = pMallocNode;
mblock->info.trunk_total_count++;
mblock->info.element_total_count += mblock->alloc_elements_once;
return 0; return 0;
} }
static inline void fast_mblock_remove_trunk(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *pMallocNode)
{
pMallocNode->prev->next = pMallocNode->next;
pMallocNode->next->prev = pMallocNode->prev;
mblock->info.trunk_total_count--;
mblock->info.element_total_count -= mblock->alloc_elements_once;
}
#define FAST_MBLOCK_GET_TRUNK(pNode) \
(struct fast_mblock_malloc *)((char *)pNode - pNode->offset)
static inline void fast_mblock_ref_counter_op(struct fast_mblock_man *mblock,
struct fast_mblock_node *pNode, const bool is_inc)
{
struct fast_mblock_malloc *pMallocNode;
pMallocNode = FAST_MBLOCK_GET_TRUNK(pNode);
if (is_inc)
{
if (pMallocNode->ref_count == 0)
{
mblock->info.trunk_used_count++;
}
pMallocNode->ref_count++;
}
else
{
pMallocNode->ref_count--;
if (pMallocNode->ref_count == 0)
{
mblock->info.trunk_used_count--;
}
}
}
#define fast_mblock_ref_counter_inc(mblock, pNode) \
fast_mblock_ref_counter_op(mblock, pNode, true)
#define fast_mblock_ref_counter_dec(mblock, pNode) \
fast_mblock_ref_counter_op(mblock, pNode, false)
void fast_mblock_destroy(struct fast_mblock_man *mblock) void fast_mblock_destroy(struct fast_mblock_man *mblock)
{ {
struct fast_mblock_malloc *pMallocNode; struct fast_mblock_malloc *pMallocNode;
struct fast_mblock_malloc *pMallocTmp; struct fast_mblock_malloc *pMallocTmp;
if (mblock->malloc_chain_head == NULL) if (IS_EMPTY(&mblock->trunks.head))
{ {
return; return;
} }
pMallocNode = mblock->malloc_chain_head; pMallocNode = mblock->trunks.head.next;
while (pMallocNode != NULL) while (pMallocNode != &mblock->trunks.head)
{ {
pMallocTmp = pMallocNode; pMallocTmp = pMallocNode;
pMallocNode = pMallocNode->next; pMallocNode = pMallocNode->next;
free(pMallocTmp); free(pMallocTmp);
} }
mblock->malloc_chain_head = NULL;
INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->free_chain_head = NULL; mblock->free_chain_head = NULL;
mblock->info.used_count = 0; mblock->info.element_used_count = 0;
mblock->info.total_count = 0; mblock->info.element_total_count = 0;
if (mblock->need_lock) pthread_mutex_destroy(&(mblock->lock)); if (mblock->need_lock) pthread_mutex_destroy(&(mblock->lock));
delete_from_mblock_list(mblock); delete_from_mblock_list(mblock);
@ -428,7 +486,9 @@ struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock)
{ {
pNode = mblock->free_chain_head; pNode = mblock->free_chain_head;
mblock->free_chain_head = pNode->next; mblock->free_chain_head = pNode->next;
mblock->info.used_count++; mblock->info.element_used_count++;
fast_mblock_ref_counter_inc(mblock, pNode);
} }
else else
{ {
@ -446,7 +506,8 @@ struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock)
{ {
pNode = mblock->free_chain_head; pNode = mblock->free_chain_head;
mblock->free_chain_head = pNode->next; mblock->free_chain_head = pNode->next;
mblock->info.used_count++; mblock->info.element_used_count++;
fast_mblock_ref_counter_inc(mblock, pNode);
} }
else else
{ {
@ -481,7 +542,8 @@ int fast_mblock_free(struct fast_mblock_man *mblock, \
pNode->next = mblock->free_chain_head; pNode->next = mblock->free_chain_head;
mblock->free_chain_head = pNode; mblock->free_chain_head = pNode;
mblock->info.used_count--; mblock->info.element_used_count--;
fast_mblock_ref_counter_dec(mblock, pNode);
if (mblock->need_lock && (result=pthread_mutex_unlock(&(mblock->lock))) != 0) if (mblock->need_lock && (result=pthread_mutex_unlock(&(mblock->lock))) != 0)
{ {
@ -576,3 +638,181 @@ int fast_mblock_delay_free_count(struct fast_mblock_man *mblock)
return fast_mblock_chain_count(mblock, mblock->delay_free_chain.head); return fast_mblock_chain_count(mblock, mblock->delay_free_chain.head);
} }
static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count,
struct fast_mblock_malloc **ppFreelist)
{
struct fast_mblock_node *pPrevious;
struct fast_mblock_node *pCurrent;
struct fast_mblock_malloc *pMallocNode;
struct fast_mblock_malloc *freelist;
bool lookup_done;
lookup_done = false;
*reclaim_count = 0;
freelist = NULL;
pPrevious = NULL;
pCurrent = mblock->free_chain_head;
mblock->free_chain_head = NULL;
while (pCurrent != NULL)
{
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
if (pMallocNode->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done))
{ //keep in free chain
if (pPrevious != NULL)
{
pPrevious->next = pCurrent;
}
else
{
mblock->free_chain_head = pCurrent;
}
pPrevious = pCurrent;
pCurrent = pCurrent->next;
if (pCurrent == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
while (pMallocNode->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done))
{
pPrevious = pCurrent;
pCurrent = pCurrent->next;
if (pCurrent == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
}
}
while (pMallocNode->ref_count < 0 ||
(pMallocNode->ref_count == 0 && !lookup_done))
{
if (pMallocNode->ref_count == 0) //trigger by the first node
{
fast_mblock_remove_trunk(mblock, pMallocNode);
pMallocNode->ref_count = -1;
pMallocNode->next = freelist;
freelist = pMallocNode;
(*reclaim_count)++;
if (*reclaim_count == reclaim_target)
{
lookup_done = true;
}
}
pCurrent = pCurrent->next;
if (pCurrent == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
}
}
OUTER:
if (pPrevious != NULL)
{
pPrevious->next = NULL;
}
{
bool old_need_lock;
old_need_lock = mblock->need_lock;
mblock->need_lock = false;
logDebug("file: "__FILE__", line: %d, "
"reclaim trunks for %p, reclaimed trunks: %d, "
"free node count: %d", __LINE__,
mblock, *reclaim_count, fast_mblock_free_count(mblock));
mblock->need_lock = mblock->need_lock;
}
*ppFreelist = freelist;
return (freelist != NULL ? 0 : ENOENT);
}
void fast_mblock_free_trunks(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist)
{
struct fast_mblock_malloc *pDeleted;
int count;
count = 0;
while (freelist != NULL)
{
pDeleted = freelist;
freelist = freelist->next;
free(pDeleted);
count++;
}
logDebug("file: "__FILE__", line: %d, "
"free_trunks for %p, free trunks: %d", __LINE__,
mblock, count);
}
int fast_mblock_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count,
fast_mblock_free_trunks_func free_trunks_func)
{
int result;
struct fast_mblock_malloc *freelist;
if (reclaim_target <= 0)
{
*reclaim_count = 0;
return EINVAL;
}
if (mblock->need_lock && (result=pthread_mutex_lock(&(mblock->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
*reclaim_count = 0;
return result;
}
if (mblock->info.trunk_total_count - mblock->info.trunk_used_count < reclaim_target)
{
*reclaim_count = 0;
result = E2BIG;
freelist = NULL;
}
else
{
result = fast_mblock_do_reclaim(mblock, reclaim_target,
reclaim_count, &freelist);
}
if (mblock->need_lock && (result=pthread_mutex_unlock(&(mblock->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
if (result == 0)
{
if (free_trunks_func != NULL)
{
free_trunks_func(mblock, freelist);
}
else
{
fast_mblock_free_trunks(mblock, freelist);
}
}
return result;
}

View File

@ -24,6 +24,7 @@
struct fast_mblock_node struct fast_mblock_node
{ {
struct fast_mblock_node *next; struct fast_mblock_node *next;
int offset; //trunk offset
int recycle_timestamp; int recycle_timestamp;
char data[0]; //the data buffer char data[0]; //the data buffer
}; };
@ -31,6 +32,8 @@ struct fast_mblock_node
/* malloc chain */ /* malloc chain */
struct fast_mblock_malloc struct fast_mblock_malloc
{ {
int64_t ref_count; //refference count
struct fast_mblock_malloc *prev;
struct fast_mblock_malloc *next; struct fast_mblock_malloc *next;
}; };
@ -45,18 +48,26 @@ struct fast_mblock_info
{ {
char name[FAST_MBLOCK_NAME_SIZE]; char name[FAST_MBLOCK_NAME_SIZE];
int element_size; //element size int element_size; //element size
int total_count; //total element count int element_total_count; //total element count
int used_count; //used element count int element_used_count; //used element count
int trunk_total_count; //total trunk count
int trunk_used_count; //used trunk count
int instance_count; //instance count int instance_count; //instance count
}; };
struct fast_mblock_trunks
{
struct fast_mblock_malloc head; //malloc chain to be freed
};
struct fast_mblock_man struct fast_mblock_man
{ {
struct fast_mblock_info info; struct fast_mblock_info info;
int alloc_elements_once; //alloc elements once int alloc_elements_once; //alloc elements once
struct fast_mblock_node *free_chain_head; //free node chain struct fast_mblock_node *free_chain_head; //free node chain
struct fast_mblock_trunks trunks;
struct fast_mblock_chain delay_free_chain; //delay free node chain struct fast_mblock_chain delay_free_chain; //delay free node chain
struct fast_mblock_malloc *malloc_chain_head; //malloc chain to be freed
fast_mblock_alloc_init_func alloc_init_func; fast_mblock_alloc_init_func alloc_init_func;
bool need_lock; //if need mutex lock bool need_lock; //if need mutex lock
pthread_mutex_t lock; //the lock for read / write free node chain pthread_mutex_t lock; //the lock for read / write free node chain
@ -233,6 +244,32 @@ return error no, 0 for success, != 0 fail
*/ */
int fast_mblock_manager_stat_print(); int fast_mblock_manager_stat_print();
typedef void (*fast_mblock_free_trunks_func)(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist);
/**
free the trunks
parameters:
mblock: the mblock pointer
freelist: the trunks to free
return error no, 0 for success, != 0 fail
*/
void fast_mblock_free_trunks(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist);
/**
reclaim the free trunks of the mblock
parameters:
mblock: the mblock pointer
reclaim_target: reclaim target trunks
reclaim_count: reclaimed trunk count
freelist: the free trunks
return error no, 0 for success, != 0 fail
*/
int fast_mblock_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count,
fast_mblock_free_trunks_func free_trunks_func);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif