diff options
author | bjj <bjj> | 1997-03-05 08:41:47 +0000 |
---|---|---|
committer | bjj <bjj> | 1997-03-05 08:41:47 +0000 |
commit | e6d92fbbd39ec6b819f4712417b6f05684e068db (patch) | |
tree | d25f4bb842ad3707e5af061fc6e9caf7c71621f8 | |
parent | 322d9846b3a375a91ab709cacdac546c7011f868 (diff) | |
download | moo-e6d92fbbd39ec6b819f4712417b6f05684e068db.tar.gz moo-e6d92fbbd39ec6b819f4712417b6f05684e068db.tar.xz moo-e6d92fbbd39ec6b819f4712417b6f05684e068db.zip |
A few malloc-friendly changes: rt_stacks are now centrally allocated/freed
so that we can keep a pool of them handy. rt_envs are similarly pooled.
Both revert to malloc/free for large requests.
-rw-r--r-- | eval_env.c | 30 | ||||
-rw-r--r-- | execute.c | 91 | ||||
-rw-r--r-- | execute.h | 15 |
3 files changed, 101 insertions, 35 deletions
@@ -22,12 +22,24 @@ #include "sym_table.h" #include "utils.h" +/* + * Keep a pool of rt_envs big enough to hold NUM_READY_VARS variables to + * avoid lots of malloc/free. + */ +static Var *ready_size_rt_envs; + Var * new_rt_env(unsigned size) { - Var *ret = mymalloc(size * sizeof(Var), M_RT_ENV); + Var *ret; unsigned i; + if (size <= NUM_READY_VARS && ready_size_rt_envs) { + ret = ready_size_rt_envs; + ready_size_rt_envs = ret[0].v.list; + } else + ret = mymalloc(MAX(size, NUM_READY_VARS) * sizeof(Var), M_RT_ENV); + for (i = 0; i < size; i++) ret[i].type = TYPE_NONE; @@ -41,7 +53,12 @@ free_rt_env(Var * rt_env, unsigned size) for (i = 0; i < size; i++) free_var(rt_env[i]); - myfree((void *) rt_env, M_RT_ENV); + + if (size <= NUM_READY_VARS) { + rt_env[0].v.list = ready_size_rt_envs; + ready_size_rt_envs = rt_env; + } else + myfree((void *) rt_env, M_RT_ENV); } Var * @@ -107,9 +124,14 @@ set_rt_env_var(Var * env, int slot, Var v) char rcsid_rt_env[] = "$Id$"; /* $Log$ -/* Revision 1.2 1997/03/03 04:18:35 nop -/* GNU Indent normalization +/* Revision 1.3 1997/03/05 08:41:50 bjj +/* A few malloc-friendly changes: rt_stacks are now centrally allocated/freed +/* so that we can keep a pool of them handy. rt_envs are similarly pooled. +/* Both revert to malloc/free for large requests. /* + * Revision 1.2 1997/03/03 04:18:35 nop + * GNU Indent normalization + * * Revision 1.1.1.1 1997/03/03 03:44:59 nop * LambdaMOO 1.8.0p5 * @@ -77,6 +77,43 @@ typedef enum { /* Reasons for executing a FINALLY handler */ FIN_EXIT } Finally_Reason; +/* + * Keep a pool of the common size rt_stacks around to avoid beating up on + * malloc. This doesn't really need tuning. Most rt_stacks will be less + * than size 10. I rounded up to a size which won't waste a lot of space + * with a powers-of-two malloc (while leaving some room for mymalloc + * overhead, if any). + */ +static Var *rt_stack_quick; +#define RT_STACK_QUICKSIZE 15 + +static void +alloc_rt_stack(activation *a, int size) +{ + Var *res; + + if (size <= RT_STACK_QUICKSIZE && rt_stack_quick) { + res = rt_stack_quick; + rt_stack_quick = rt_stack_quick[0].v.list; + } else { + res = mymalloc(MAX(size, RT_STACK_QUICKSIZE) * sizeof(Var), M_RT_STACK); + } + a->base_rt_stack = a->top_rt_stack = res; + a->rt_stack_size = size; +} + +static void +free_rt_stack(activation *a) +{ + Var *stack = a->base_rt_stack; + + if (a->rt_stack_size <= RT_STACK_QUICKSIZE) { + stack[0].v.list = rt_stack_quick; + rt_stack_quick = stack; + } else + myfree(stack, M_RT_STACK); +} + void print_error_backtrace(const char *msg, void (*output) (const char *)) { @@ -480,7 +517,7 @@ free_activation(activation a, char data_too) for (i = a.base_rt_stack; i < a.top_rt_stack; i++) free_var(*i); - myfree((void *) a.base_rt_stack, M_RT_STACK); + free_rt_stack(&a); free_var(a.temp); free_str(a.verb); free_str(a.verbname); @@ -540,8 +577,7 @@ call_verb(Objid this, const char *vname, Var args, int do_pass) RUN_ACTIV.verbname = str_ref(db_verb_names(h)); RUN_ACTIV.debug = (db_verb_flags(h) & VF_DEBUG); - RUN_ACTIV.top_rt_stack = RUN_ACTIV.base_rt_stack - = mymalloc(program->main_vector.max_stack * sizeof(Var), M_RT_STACK); + alloc_rt_stack(&RUN_ACTIV, program->main_vector.max_stack); RUN_ACTIV.pc = 0; RUN_ACTIV.error_pc = 0; RUN_ACTIV.bi_func_pc = 0; @@ -634,7 +670,7 @@ bi_prop_protected(enum bi_prop prop, Objid progr) return server_flag_option(pname); } -#endif /* IGNORE_PROP_PROTECTED */ +#endif /* IGNORE_PROP_PROTECTED */ /** the main interpreter -- run() @@ -2089,11 +2125,9 @@ do_task(Program * prog, int which_vector, Var * result, int do_db_tracebacks) RUN_ACTIV.prog = program_ref(prog); root_activ_vector = which_vector; /* main or which of the forked */ - RUN_ACTIV.top_rt_stack = RUN_ACTIV.base_rt_stack - = mymalloc((which_vector == MAIN_VECTOR - ? prog->main_vector.max_stack - : prog->fork_vectors[which_vector].max_stack) * - sizeof(Var), M_RT_STACK); + alloc_rt_stack(&RUN_ACTIV, (which_vector == MAIN_VECTOR + ? prog->main_vector.max_stack + : prog->fork_vectors[which_vector].max_stack)); RUN_ACTIV.pc = 0; RUN_ACTIV.error_pc = 0; @@ -2260,9 +2294,7 @@ setup_activ_for_eval(Program * prog) RUN_ACTIV.verb = str_dup(""); RUN_ACTIV.verbname = str_dup("Input to EVAL"); RUN_ACTIV.debug = 1; - RUN_ACTIV.top_rt_stack = RUN_ACTIV.base_rt_stack - = mymalloc(RUN_ACTIV.prog->main_vector.max_stack * sizeof(Var), - M_RT_STACK); + alloc_rt_stack(&RUN_ACTIV, RUN_ACTIV.prog->main_vector.max_stack); RUN_ACTIV.pc = 0; RUN_ACTIV.error_pc = 0; RUN_ACTIV.temp.type = TYPE_NONE; @@ -2730,7 +2762,7 @@ read_activ(activation * a, int which_vector) max_stack = (which_vector == MAIN_VECTOR ? a->prog->main_vector.max_stack : a->prog->fork_vectors[which_vector].max_stack); - a->base_rt_stack = mymalloc(max_stack * sizeof(Var), M_RT_STACK); + alloc_rt_stack(a, max_stack); if (dbio_scanf("%d rt_stack slots in use\n", &stack_in_use) != 1) { errlog("READ_ACTIV: Bad stack_in_use number\n"); @@ -2783,21 +2815,26 @@ read_activ(activation * a, int which_vector) char rcsid_execute[] = "$Id$"; /* $Log$ -/* Revision 1.4 1997/03/03 09:03:31 bjj -/* 3 opcode optimizations: -/* -/* 1) OP_IMM+OP_POP is "peephole optimized" away at runtime. This makes -/* verbdocs and other comments cheaper. -/* -/* 2) OP_PUT_n+OP_POP is similarly optimized (PUT doesn't consume the -/* top value on the stack but it is often used that way in statements like -/* `var = expr;'). OP_G_PUT could use the same change but is rarely -/* executed. -/* -/* 3) OP_PUT_n, OP_PUSH_n which used to be in an if/else in the default -/* case are split out into 32 cases each so the compiler can optimize it -/* for us. These ops account for a large percentage of those executed. +/* Revision 1.5 1997/03/05 08:41:47 bjj +/* A few malloc-friendly changes: rt_stacks are now centrally allocated/freed +/* so that we can keep a pool of them handy. rt_envs are similarly pooled. +/* Both revert to malloc/free for large requests. /* + * Revision 1.4 1997/03/03 09:03:31 bjj + * 3 opcode optimizations: + * + * 1) OP_IMM+OP_POP is "peephole optimized" away at runtime. This makes + * verbdocs and other comments cheaper. + * + * 2) OP_PUT_n+OP_POP is similarly optimized (PUT doesn't consume the + * top value on the stack but it is often used that way in statements like + * `var = expr;'). OP_G_PUT could use the same change but is rarely + * executed. + * + * 3) OP_PUT_n, OP_PUSH_n which used to be in an if/else in the default + * case are split out into 32 cases each so the compiler can optimize it + * for us. These ops account for a large percentage of those executed. + * * Revision 1.3 1997/03/03 06:14:44 nop * Nobody actually uses protected properties. Make IGNORE_PROP_PROTECTED * the default. @@ -29,9 +29,11 @@ typedef struct { Program *prog; Var *rt_env; /* same length as prog.var_names */ Var *base_rt_stack; - Var *top_rt_stack; /* the stack has a fixed size equal to prog.num_var_names; - top_rt_stack always points to next empty slot; + Var *top_rt_stack; /* the stack has a fixed size equal to + vector.max_stack. top_rt_stack + always points to next empty slot; there is no need to check bounds! */ + int rt_stack_size; /* size of stack allocated */ unsigned pc; unsigned error_pc; Byte bi_func_pc; /* next == 0 means a normal activation, which just @@ -128,9 +130,14 @@ extern int read_activ(activation * a, int which_vector); #endif /* $Log$ -/* Revision 1.2 1997/03/03 04:18:40 nop -/* GNU Indent normalization +/* Revision 1.3 1997/03/05 08:41:49 bjj +/* A few malloc-friendly changes: rt_stacks are now centrally allocated/freed +/* so that we can keep a pool of them handy. rt_envs are similarly pooled. +/* Both revert to malloc/free for large requests. /* + * Revision 1.2 1997/03/03 04:18:40 nop + * GNU Indent normalization + * * Revision 1.1.1.1 1997/03/03 03:45:03 nop * LambdaMOO 1.8.0p5 * |