aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbjj <bjj>1997-03-05 08:41:47 +0000
committerbjj <bjj>1997-03-05 08:41:47 +0000
commite6d92fbbd39ec6b819f4712417b6f05684e068db (patch)
treed25f4bb842ad3707e5af061fc6e9caf7c71621f8
parent322d9846b3a375a91ab709cacdac546c7011f868 (diff)
downloadmoo-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.c30
-rw-r--r--execute.c91
-rw-r--r--execute.h15
3 files changed, 101 insertions, 35 deletions
diff --git a/eval_env.c b/eval_env.c
index a74e688..7b28ac6 100644
--- a/eval_env.c
+++ b/eval_env.c
@@ -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
*
diff --git a/execute.c b/execute.c
index fa06ea1..638a46f 100644
--- a/execute.c
+++ b/execute.c
@@ -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.
diff --git a/execute.h b/execute.h
index c9f51a7..82b0db7 100644
--- a/execute.h
+++ b/execute.h
@@ -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
*