[asterisk-commits] murf: branch murf/fast-ast r44910 -
/team/murf/fast-ast/main/pbx.c
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Wed Oct 11 21:53:18 MST 2006
Author: murf
Date: Wed Oct 11 23:53:18 2006
New Revision: 44910
URL: http://svn.digium.com/view/asterisk?rev=44910&view=rev
Log:
performance enhancement gives 1.19x improvement
Modified:
team/murf/fast-ast/main/pbx.c
Modified: team/murf/fast-ast/main/pbx.c
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast/main/pbx.c?rev=44910&r1=44909&r2=44910&view=diff
==============================================================================
--- team/murf/fast-ast/main/pbx.c (original)
+++ team/murf/fast-ast/main/pbx.c Wed Oct 11 23:53:18 2006
@@ -70,6 +70,18 @@
* aspects of this PBX. The switching scheme as it exists right now isn't
* terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
* of priorities, but a constant search time here would be great ;-)
+ *
+ * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
+ * here, and shows a fairly flat (constant) search time, even for as many as
+ * 1000 patterns. Still needs some work-- doesn't handle matchcid yet, but
+ * that's no big problem, it will not be difficult to add...
+ *
+ * Also, using a hash table for context/priority name lookup can help prevent
+ * the find_extension routines from absorbing exponential cpu cycles. Right now,
+ * I'm using red-black balanced binary trees, log(n) search time.
+ *
+ * A simple hack to prevent repetitive calls to find_extension when it isn't
+ * necessary has been added.
*
*/
@@ -2079,7 +2091,7 @@
*/
static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
const char *context, const char *exten, int priority,
- const char *label, const char *callerid, enum ext_match_t action)
+ const char *label, const char *callerid, enum ext_match_t action, struct ast_exten **target)
{
struct ast_exten *e;
struct ast_app *app;
@@ -2090,8 +2102,13 @@
int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
ast_mutex_lock(&conlock);
- e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
+ if (target && *target)
+ e = *target;
+ else
+ e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
if (e) {
+ if (target && action != E_SPAWN)
+ *target = e;
if (matching_action) {
ast_mutex_unlock(&conlock);
return -1; /* success, we found it */
@@ -2572,32 +2589,32 @@
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, NULL);
}
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
{
- return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
+ return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, NULL);
}
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
{
- return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
+ return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, NULL);
}
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH,NULL);
}
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, NULL);
}
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, NULL);
}
/* helper function to set extension and priority */
@@ -2693,11 +2710,24 @@
char dst_exten[256]; /* buffer to accumulate digits */
int pos = 0; /* XXX should check bounds */
int digit = 0;
+ char *last_context = 0;
+ char *last_extension = 0;
+ int last_priority = 0;
+ struct ast_exten *target=0;
/* loop on priorities in this context/exten */
- while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- found = 1;
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
+ /* we call pbx_extension_helper(...E_MATCH..) here, instead of ast_exists_extension, to avoid
+ * forcing an extension search, if we already know where the ast_extension is!
+ */
+ while (pbx_extension_helper(c, NULL, c->context, c->exten, c->priority, NULL, c->cid.cid_num, E_MATCH, &target)) {
+ found = 1;
+ last_context = c->context;
+ last_extension = c->exten;
+ last_priority = c->priority;
+ /* we call pbx_extension_helper(...E_SPAWN...) here instead of ast_spawn_extension, so we can use
+ * the extension previously looked up instead of forcing a fresh search for extension
+ */
+ if ((res = pbx_extension_helper(c, NULL, c->context, c->exten, c->priority, NULL, c->cid.cid_num, E_SPAWN, &target))) {
/* Something bad happened, or a hangup has been requested. */
if (strchr("0123456789ABCDEF*#", res)) {
if (option_debug)
@@ -2743,6 +2773,14 @@
break;
}
c->priority++;
+ /* the following line avoids wasteful searches for extension, because, if we are merely going
+ * to the next extension, it's already at the peer pointer on the extension we just ran! If all
+ * the planets are in alignment, set the target to point to the next extension, and we won't be searching!
+ */
+ if (c->context == last_context && c->exten == last_extension && c->priority == last_priority+1 && target && target->peer && target->peer->priority == c->priority)
+ target = target->peer;
+ else
+ target = 0;
} /* end while - from here on we can use 'break' to go out */
if (error)
break;
More information about the asterisk-commits
mailing list