diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-29 20:50:36 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-08-29 20:50:36 +0000 |
commit | 53f8d43e2945038fe3059fd6c1c00dd4ec117505 (patch) | |
tree | 0f3fc04bcb07ac328d54ffb2fed0333dfffb44de /channels/iax2-parser.c | |
parent | 562decf81af443d24afd3f1fc3d133b8b2b7cee3 (diff) |
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: http://svn.digium.com/svn/asterisk/trunk@41278 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/iax2-parser.c')
-rw-r--r-- | channels/iax2-parser.c | 82 |
1 files changed, 70 insertions, 12 deletions
diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c index 67341fc5e..94aaf4c70 100644 --- a/channels/iax2-parser.c +++ b/channels/iax2-parser.c @@ -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; } |