[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