aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauri Kasanen <cand@gmx.com>2013-03-09 12:00:33 +0200
committerSteve Bennett <steveb@workware.net.au>2013-03-12 09:00:19 +1000
commit69f1b01e204f538283ef575691c35e76b99f25df (patch)
treec62213a45ca4b3647cae10d21086716d84586ed1
parent9d4f23daa022c9ca012fb65606960b64b22febe5 (diff)
downloadjimtcl-69f1b01e204f538283ef575691c35e76b99f25df.zip
jimtcl-69f1b01e204f538283ef575691c35e76b99f25df.tar.gz
jimtcl-69f1b01e204f538283ef575691c35e76b99f25df.tar.bz2
Precompute operator length for JimParseExprOperator, optimize logic
No regressions, no changes in bench.tcl. JimParseExprOperator was shockingly inefficient, to the point of taking 63% of cpu in my own app. It did a linear search over >60 structs, re-computing the string length each time, and doing a string comparison for each. This patch pre-computes the operator string length, speeding the function up by two. Adding the first-letter fast path and evaluating length before strncmp make for another 2x speedup, making the total speedup 4x. Signed-off-by: Lauri Kasanen <cand@gmx.com>
-rw-r--r--jim.c140
1 files changed, 72 insertions, 68 deletions
diff --git a/jim.c b/jim.c
index fe6ca50..c52199e 100644
--- a/jim.c
+++ b/jim.c
@@ -7378,6 +7378,7 @@ typedef struct Jim_ExprOperator
int arity;
int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
int lazy;
+ unsigned char namelen;
} Jim_ExprOperator;
static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
@@ -8077,91 +8078,96 @@ enum
/* name - precedence - arity - opcode
*
- * This array *must* be kept in sync with the JIM_EXPROP enum
+ * This array *must* be kept in sync with the JIM_EXPROP enum.
+ *
+ * The following macro pre-computes the string length at compile time.
*/
+#define OPRINIT(a, b, c, d, e) {a, b, c, d, e, sizeof(a) - 1}
+
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
- {"*", 200, 2, JimExprOpBin, LAZY_NONE},
- {"/", 200, 2, JimExprOpBin, LAZY_NONE},
- {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
+ OPRINIT("*", 200, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT("/", 200, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT("%", 200, 2, JimExprOpIntBin, LAZY_NONE),
- {"-", 100, 2, JimExprOpBin, LAZY_NONE},
- {"+", 100, 2, JimExprOpBin, LAZY_NONE},
+ OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE),
- {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
- {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+ OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
+ OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE),
- {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
- {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+ OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
+ OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE),
- {"<", 80, 2, JimExprOpBin, LAZY_NONE},
- {">", 80, 2, JimExprOpBin, LAZY_NONE},
- {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
- {">=", 80, 2, JimExprOpBin, LAZY_NONE},
+ OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE),
- {"==", 70, 2, JimExprOpBin, LAZY_NONE},
- {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
+ OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE),
+ OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE),
- {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
- {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
- {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
+ OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE),
+ OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE),
+ OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE),
- {"&&", 10, 2, NULL, LAZY_OP},
- {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
- {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+ OPRINIT("&&", 10, 2, NULL, LAZY_OP),
+ OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
+ OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
- {"||", 9, 2, NULL, LAZY_OP},
- {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
- {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+ OPRINIT("||", 9, 2, NULL, LAZY_OP),
+ OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
+ OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
- {"?", 5, 2, JimExprOpNull, LAZY_OP},
- {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
- {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+ OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP),
+ OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
+ OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
- {":", 5, 2, JimExprOpNull, LAZY_OP},
- {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
- {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+ OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP),
+ OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
+ OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
- {"**", 250, 2, JimExprOpBin, LAZY_NONE},
+ OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE),
- {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
- {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
+ OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE),
+ OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE),
- {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
- {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
+ OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE),
+ OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE),
- {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
- {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
- {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
- {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+ OPRINIT("!", 300, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT("~", 300, 1, JimExprOpIntUnary, LAZY_NONE),
+ OPRINIT(NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT(NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE),
- {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
- {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
- {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
- {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
- {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
- {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
+ OPRINIT("int", 400, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT("abs", 400, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT("double", 400, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT("round", 400, 1, JimExprOpNumUnary, LAZY_NONE),
+ OPRINIT("rand", 400, 0, JimExprOpNone, LAZY_NONE),
+ OPRINIT("srand", 400, 1, JimExprOpIntUnary, LAZY_NONE),
#ifdef JIM_MATH_FUNCTIONS
- {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
- {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
+ OPRINIT("sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE),
+ OPRINIT("pow", 400, 2, JimExprOpBin, LAZY_NONE),
#endif
};
+#undef OPRINIT
#define JIM_EXPR_OPERATORS_NUM \
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
@@ -8331,16 +8337,14 @@ static int JimParseExprOperator(struct JimParserCtx *pc)
/* Try to get the longest match. */
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
- const char *opname;
- int oplen;
+ const char * const opname = Jim_ExprOperators[i].name;
+ const int oplen = Jim_ExprOperators[i].namelen;
- opname = Jim_ExprOperators[i].name;
- if (opname == NULL) {
+ if (opname == NULL || opname[0] != pc->p[0]) {
continue;
}
- oplen = strlen(opname);
- if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
+ if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
bestIdx = i + JIM_TT_EXPR_OP;
bestLen = oplen;
}