Filter refactoring: The values are now saved on a custom stack.
This shall help with performance.
This commit is contained in:
parent
7afa143886
commit
fc8df41ec6
2 changed files with 55 additions and 28 deletions
|
@ -121,15 +121,14 @@
|
||||||
while (tt) {
|
while (tt) {
|
||||||
*vv = lp_alloc(fs->pool, sizeof(struct f_path_mask));
|
*vv = lp_alloc(fs->pool, sizeof(struct f_path_mask));
|
||||||
if (tt->kind == PM_ASN_EXPR) {
|
if (tt->kind == PM_ASN_EXPR) {
|
||||||
struct f_val xres;
|
INTERPRET((struct f_inst *) tt->val, 0);
|
||||||
INTERPRET(xres, (struct f_inst *) tt->val);
|
|
||||||
(*vv)->kind = PM_ASN;
|
(*vv)->kind = PM_ASN;
|
||||||
if (xres.type != T_INT) {
|
if (res.type != T_INT) {
|
||||||
runtime( "Error resolving path mask template: value not an integer" );
|
runtime( "Error resolving path mask template: value not an integer" );
|
||||||
return F_ERROR;
|
return F_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*vv)->val = xres.val.i;
|
(*vv)->val = res.val.i;
|
||||||
} else {
|
} else {
|
||||||
**vv = *tt;
|
**vv = *tt;
|
||||||
}
|
}
|
||||||
|
@ -659,7 +658,7 @@
|
||||||
return F_RETURN;
|
return F_RETURN;
|
||||||
case FI_CALL:
|
case FI_CALL:
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
fret = interpret(fs, what->a2.p, &res);
|
fret = interpret(fs, what->a2.p);
|
||||||
if (fret > F_RETURN)
|
if (fret > F_RETURN)
|
||||||
return fret;
|
return fret;
|
||||||
break;
|
break;
|
||||||
|
@ -681,7 +680,9 @@
|
||||||
}
|
}
|
||||||
/* It is actually possible to have t->data NULL */
|
/* It is actually possible to have t->data NULL */
|
||||||
|
|
||||||
INTERPRET(res, t->data);
|
fret = interpret(fs, t->data);
|
||||||
|
if (fret >= F_RETURN)
|
||||||
|
return fret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FI_IP_MASK: /* IP.MASK(val) */
|
case FI_IP_MASK: /* IP.MASK(val) */
|
||||||
|
|
|
@ -50,6 +50,15 @@
|
||||||
|
|
||||||
#define CMP_ERROR 999
|
#define CMP_ERROR 999
|
||||||
|
|
||||||
|
#define FILTER_STACK_DEPTH 16384
|
||||||
|
|
||||||
|
/* Filter interpreter stack. Make this thread local after going parallel. */
|
||||||
|
struct filter_stack {
|
||||||
|
struct f_val val;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct filter_stack filter_stack[FILTER_STACK_DEPTH];
|
||||||
|
|
||||||
/* Internal filter state, to be allocated on stack when executing filters */
|
/* Internal filter state, to be allocated on stack when executing filters */
|
||||||
struct filter_state {
|
struct filter_state {
|
||||||
struct rte **rte;
|
struct rte **rte;
|
||||||
|
@ -57,6 +66,8 @@ struct filter_state {
|
||||||
struct ea_list **eattrs;
|
struct ea_list **eattrs;
|
||||||
struct linpool *pool;
|
struct linpool *pool;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
|
struct filter_stack *stack;
|
||||||
|
int stack_ptr;
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -611,24 +622,25 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
|
||||||
* are either integers, or pointers to instruction trees. Common
|
* are either integers, or pointers to instruction trees. Common
|
||||||
* instructions like +, that have two expressions as arguments use
|
* instructions like +, that have two expressions as arguments use
|
||||||
* TWOARGS macro to get both of them evaluated.
|
* TWOARGS macro to get both of them evaluated.
|
||||||
*
|
|
||||||
* &f_val structures are copied around, so there are no problems with
|
|
||||||
* memory managment.
|
|
||||||
*/
|
*/
|
||||||
static enum filter_return
|
static enum filter_return
|
||||||
interpret(struct filter_state *fs, struct f_inst *what, struct f_val *resp)
|
interpret(struct filter_state *fs, struct f_inst *what)
|
||||||
{
|
{
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
struct f_val v1, v2, v3, *vp;
|
struct f_val *vp;
|
||||||
unsigned u1, u2;
|
unsigned u1, u2;
|
||||||
enum filter_return fret;
|
enum filter_return fret;
|
||||||
int i;
|
int i;
|
||||||
u32 as;
|
u32 as;
|
||||||
|
|
||||||
*resp = (struct f_val) { .type = T_VOID };
|
#define res fs->stack[fs->stack_ptr].val
|
||||||
|
#define v1 fs->stack[fs->stack_ptr + 1].val
|
||||||
|
#define v2 fs->stack[fs->stack_ptr + 2].val
|
||||||
|
#define v3 fs->stack[fs->stack_ptr + 3].val
|
||||||
|
|
||||||
|
res = (struct f_val) { .type = T_VOID };
|
||||||
|
|
||||||
for ( ; what; what = what->next) {
|
for ( ; what; what = what->next) {
|
||||||
#define res (*resp)
|
|
||||||
res = (struct f_val) { .type = T_VOID };
|
res = (struct f_val) { .type = T_VOID };
|
||||||
switch(what->fi_code) {
|
switch(what->fi_code) {
|
||||||
|
|
||||||
|
@ -638,17 +650,22 @@ interpret(struct filter_state *fs, struct f_inst *what, struct f_val *resp)
|
||||||
return F_ERROR; \
|
return F_ERROR; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define ARG_ANY(n) INTERPRET(v##n, what->a##n.p)
|
#define ARG_ANY(n) INTERPRET(what->a##n.p, n)
|
||||||
|
|
||||||
#define ARG(n,t) ARG_ANY(n) \
|
#define ARG(n,t) ARG_ANY(n); \
|
||||||
if (v##n.type != t) \
|
if (v##n.type != t) \
|
||||||
runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
|
runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
|
||||||
n, f_instruction_name(what->fi_code), t, v##n.type);
|
n, f_instruction_name(what->fi_code), t, v##n.type);
|
||||||
|
|
||||||
#define INTERPRET(val, what_) \
|
#define INTERPRET(what_, n) do { \
|
||||||
fret = interpret(fs, what_, &(val)); \
|
fs->stack_ptr += n; \
|
||||||
if (fret >= F_RETURN) \
|
fret = interpret(fs, what_); \
|
||||||
return fret;
|
fs->stack_ptr -= n; \
|
||||||
|
if (fret == F_RETURN) \
|
||||||
|
bug("This shall not happen"); \
|
||||||
|
if (fret > F_RETURN) \
|
||||||
|
return fret; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define ACCESS_RTE \
|
#define ACCESS_RTE \
|
||||||
do { if (!fs->rte) runtime("No route to access"); } while (0)
|
do { if (!fs->rte) runtime("No route to access"); } while (0)
|
||||||
|
@ -857,12 +874,12 @@ f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int fla
|
||||||
.rte = rte,
|
.rte = rte,
|
||||||
.pool = tmp_pool,
|
.pool = tmp_pool,
|
||||||
.flags = flags,
|
.flags = flags,
|
||||||
|
.stack = filter_stack,
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_BUFFER_INIT(fs.buf);
|
LOG_BUFFER_INIT(fs.buf);
|
||||||
|
|
||||||
struct f_val res;
|
enum filter_return fret = interpret(&fs, filter->root);
|
||||||
enum filter_return fret = interpret(&fs, filter->root, &res);
|
|
||||||
|
|
||||||
if (fs.old_rta) {
|
if (fs.old_rta) {
|
||||||
/*
|
/*
|
||||||
|
@ -902,13 +919,13 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
|
||||||
struct filter_state fs = {
|
struct filter_state fs = {
|
||||||
.rte = rte,
|
.rte = rte,
|
||||||
.pool = tmp_pool,
|
.pool = tmp_pool,
|
||||||
|
.stack = filter_stack,
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_BUFFER_INIT(fs.buf);
|
LOG_BUFFER_INIT(fs.buf);
|
||||||
|
|
||||||
/* Note that in this function we assume that rte->attrs is private / uncached */
|
/* Note that in this function we assume that rte->attrs is private / uncached */
|
||||||
struct f_val res;
|
return interpret(&fs, expr);
|
||||||
return interpret(&fs, expr, &res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum filter_return
|
enum filter_return
|
||||||
|
@ -916,25 +933,34 @@ f_eval(struct f_inst *expr, struct linpool *tmp_pool, struct f_val *pres)
|
||||||
{
|
{
|
||||||
struct filter_state fs = {
|
struct filter_state fs = {
|
||||||
.pool = tmp_pool,
|
.pool = tmp_pool,
|
||||||
|
.stack = filter_stack,
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_BUFFER_INIT(fs.buf);
|
LOG_BUFFER_INIT(fs.buf);
|
||||||
|
|
||||||
return interpret(&fs, expr, pres);
|
enum filter_return fret = interpret(&fs, expr);
|
||||||
|
*pres = filter_stack[0].val;
|
||||||
|
return fret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
uint
|
||||||
f_eval_int(struct f_inst *expr)
|
f_eval_int(struct f_inst *expr)
|
||||||
{
|
{
|
||||||
/* Called independently in parse-time to eval expressions */
|
/* Called independently in parse-time to eval expressions */
|
||||||
struct f_val res;
|
struct filter_state fs = {
|
||||||
if (f_eval(expr, cfg_mem, &res) > F_RETURN)
|
.pool = cfg_mem,
|
||||||
|
.stack = filter_stack,
|
||||||
|
};
|
||||||
|
|
||||||
|
LOG_BUFFER_INIT(fs.buf);
|
||||||
|
|
||||||
|
if (interpret(&fs, expr) > F_RETURN)
|
||||||
cf_error("Runtime error while evaluating expression");
|
cf_error("Runtime error while evaluating expression");
|
||||||
|
|
||||||
if (res.type != T_INT)
|
if (filter_stack[0].val.type != T_INT)
|
||||||
cf_error("Integer expression expected");
|
cf_error("Integer expression expected");
|
||||||
|
|
||||||
return res.val.i;
|
return filter_stack[0].val.val.i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue