mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
Merge team/russell/frame_caching
There are some situations in Asterisk where ast_frame and/or iax_frame structures are rapidly allocatted and freed (at least 50 times per second for one call). This code significantly improves the performance of ast_frame_header_new(), ast_frdup(), ast_frfree(), iax_frame_new(), and iax_frame_free() by keeping a thread-local cache of these structures and using frames from the cache whenever possible instead of calling malloc/free every time. This commit also converts the ast_frame and iax_frame structures to use the linked list macros. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@41278 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/unaligned.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/threadstorage.h"
|
||||
|
||||
#include "iax2.h"
|
||||
#include "iax2-parser.h"
|
||||
@@ -49,6 +50,15 @@ static int frames = 0;
|
||||
static int iframes = 0;
|
||||
static int oframes = 0;
|
||||
|
||||
static void frame_cache_cleanup(void *data);
|
||||
|
||||
/*! \brief A per-thread cache of iax_frame structures */
|
||||
AST_THREADSTORAGE_CUSTOM(frame_cache, frame_cache_init, frame_cache_cleanup);
|
||||
|
||||
/*! \brief This is just so iax_frames, a list head struct for holding a list of
|
||||
* iax_frame structures, is defined. */
|
||||
AST_LIST_HEAD_NOLOCK(iax_frames, iax_frame);
|
||||
|
||||
static void internaloutput(const char *str)
|
||||
{
|
||||
fputs(str, stdout);
|
||||
@@ -926,22 +936,44 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
|
||||
|
||||
struct iax_frame *iax_frame_new(int direction, int datalen)
|
||||
{
|
||||
struct iax_frame *fr;
|
||||
fr = malloc((int)sizeof(struct iax_frame) + datalen);
|
||||
if (fr) {
|
||||
fr->direction = direction;
|
||||
fr->retrans = -1;
|
||||
ast_atomic_fetchadd_int(&frames, 1);
|
||||
if (fr->direction == DIRECTION_INGRESS)
|
||||
ast_atomic_fetchadd_int(&iframes, 1);
|
||||
else
|
||||
ast_atomic_fetchadd_int(&oframes, 1);
|
||||
struct iax_frame *fr = NULL;
|
||||
struct iax_frames *iax_frames;
|
||||
|
||||
/* Attempt to get a frame from this thread's cache */
|
||||
if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(iax_frames, fr, list) {
|
||||
if (fr->mallocd_datalen >= datalen) {
|
||||
size_t mallocd_datalen = fr->mallocd_datalen;
|
||||
AST_LIST_REMOVE_CURRENT(iax_frames, list);
|
||||
memset(fr, 0, sizeof(*fr));
|
||||
fr->mallocd_datalen = mallocd_datalen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END
|
||||
}
|
||||
|
||||
if (!fr) {
|
||||
if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
|
||||
return NULL;
|
||||
fr->mallocd_datalen = datalen;
|
||||
}
|
||||
|
||||
fr->direction = direction;
|
||||
fr->retrans = -1;
|
||||
|
||||
if (fr->direction == DIRECTION_INGRESS)
|
||||
ast_atomic_fetchadd_int(&iframes, 1);
|
||||
else
|
||||
ast_atomic_fetchadd_int(&oframes, 1);
|
||||
|
||||
return fr;
|
||||
}
|
||||
|
||||
void iax_frame_free(struct iax_frame *fr)
|
||||
static void __iax_frame_free(struct iax_frame *fr, int cache)
|
||||
{
|
||||
struct iax_frames *iax_frames;
|
||||
|
||||
/* Note: does not remove from scheduler! */
|
||||
if (fr->direction == DIRECTION_INGRESS)
|
||||
ast_atomic_fetchadd_int(&iframes, -1);
|
||||
@@ -952,8 +984,34 @@ void iax_frame_free(struct iax_frame *fr)
|
||||
return;
|
||||
}
|
||||
fr->direction = 0;
|
||||
free(fr);
|
||||
ast_atomic_fetchadd_int(&frames, -1);
|
||||
if (!cache) {
|
||||
free(fr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
|
||||
free(fr);
|
||||
return;
|
||||
}
|
||||
|
||||
AST_LIST_INSERT_HEAD(iax_frames, fr, list);
|
||||
}
|
||||
|
||||
static void frame_cache_cleanup(void *data)
|
||||
{
|
||||
struct iax_frames *frames = data;
|
||||
struct iax_frame *cur;
|
||||
|
||||
while ((cur = AST_LIST_REMOVE_HEAD(frames, list)))
|
||||
__iax_frame_free(cur, 0);
|
||||
|
||||
free(frames);
|
||||
}
|
||||
|
||||
void iax_frame_free(struct iax_frame *fr)
|
||||
{
|
||||
__iax_frame_free(fr, 1);
|
||||
}
|
||||
|
||||
int iax_get_frames(void) { return frames; }
|
||||
|
Reference in New Issue
Block a user