Skip to content
Snippets Groups Projects
Commit a456c65d authored by Fredrik Hübinette (Hubbe)'s avatar Fredrik Hübinette (Hubbe)
Browse files

added some hash tables to speed up {find,remove}_call_out

Rev: src/modules/call_out/call_out.c:1.21
parent f92550c8
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
||| See the files COPYING and DISCLAIMER for more information. ||| See the files COPYING and DISCLAIMER for more information.
\*/ \*/
#include "global.h" #include "global.h"
RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $"); RCSID("$Id: call_out.c,v 1.21 1998/05/22 00:34:16 hubbe Exp $");
#include "array.h" #include "array.h"
#include "dynamic_buffer.h" #include "dynamic_buffer.h"
#include "object.h" #include "object.h"
...@@ -20,6 +20,7 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $"); ...@@ -20,6 +20,7 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $");
#include "builtin_functions.h" #include "builtin_functions.h"
#include "gc.h" #include "gc.h"
#include "threads.h" #include "threads.h"
#include "stuff.h"
#include "callback.h" #include "callback.h"
...@@ -31,17 +32,58 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $"); ...@@ -31,17 +32,58 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $");
struct call_out_s struct call_out_s
{ {
INT32 pos;
struct timeval tv; struct timeval tv;
struct call_out_s *next; /* For block alloc */
struct call_out_s *next_fun;
struct call_out_s **prev_fun;
struct call_out_s *next_arr;
struct call_out_s **prev_arr;
struct object *caller; struct object *caller;
struct array *args; struct array *args;
}; };
#include "block_alloc.h"
#ifdef DEBUG
#define MESS_UP_BLOCK(X) \
(X)->next_arr=(struct call_out_s *)-1; \
(X)->next_fun=(struct call_out_s *)-1; \
(X)->prev_arr=(struct call_out_s **)-1; \
(X)->prev_fun=(struct call_out_s **)-1; \
(X)->caller=(struct object *)-1; \
(X)->args=(struct array *)-1; \
(X)->pos=-1;
#else
#define MESS_UP_BLOCK(X)
#endif
#undef EXIT_BLOCK
#define EXIT_BLOCK(X) \
*(X->prev_arr)=X->next_arr; \
if(X->next_arr) X->next_arr->prev_arr=X->prev_arr; \
*(X->prev_fun)=X->next_fun; \
if(X->next_fun) X->next_fun->prev_fun=X->prev_fun; \
MESS_UP_BLOCK(X) ;
BLOCK_ALLOC(call_out_s, 1022 )
typedef struct call_out_s call_out; typedef struct call_out_s call_out;
struct hash_ent
{
call_out *arr;
call_out *fun;
};
int num_pending_calls; /* no of busy pointers in buffer */ int num_pending_calls; /* no of busy pointers in buffer */
static call_out *call_buffer=0; /* pointer to buffer */ static call_out **call_buffer=0; /* pointer to buffer */
static int call_buffer_size; /* no of pointers in buffer */ static int call_buffer_size; /* no of pointers in buffer */
static unsigned int hash_size=0;
static unsigned int hash_order=7;
static struct hash_ent *call_hash=0;
#undef CAR #undef CAR
#undef CDR #undef CDR
...@@ -49,8 +91,9 @@ static int call_buffer_size; /* no of pointers in buffer */ ...@@ -49,8 +91,9 @@ static int call_buffer_size; /* no of pointers in buffer */
#define CDR(X) (((X)<<1)+2) #define CDR(X) (((X)<<1)+2)
#define PARENT(X) (((X)-1)>>1) #define PARENT(X) (((X)-1)>>1)
#define CALL(X) (call_buffer[(X)]) #define CALL(X) (call_buffer[(X)])
#define CMP(X,Y) my_timercmp(& CALL(X).tv, <, & CALL(Y).tv) #define MOVECALL(X,Y) do { INT32 p_=(X); (CALL(p_)=CALL(Y))->pos=p_; }while(0)
#define SWAP(X,Y) do{ call_out _tmp=CALL(X); CALL(X)=CALL(Y); CALL(Y)=_tmp; } while(0) #define CMP(X,Y) my_timercmp(& CALL(X)->tv, <, & CALL(Y)->tv)
#define SWAP(X,Y) do{ call_out *_tmp=CALL(X); (CALL(X)=CALL(Y))->pos=(X); (CALL(Y)=_tmp)->pos=(Y); } while(0)
#ifdef DEBUG #ifdef DEBUG
static int inside_call_out=0; static int inside_call_out=0;
...@@ -85,7 +128,7 @@ static void verify_call_outs(void) ...@@ -85,7 +128,7 @@ static void verify_call_outs(void)
fatal("Error in call out heap. (@ %d)\n",e); fatal("Error in call out heap. (@ %d)\n",e);
} }
if(!(v=CALL(e).args)) if(!(v=CALL(e)->args))
fatal("No arguments to call\n"); fatal("No arguments to call\n");
if(v->refs < 1) if(v->refs < 1)
...@@ -97,21 +140,50 @@ static void verify_call_outs(void) ...@@ -97,21 +140,50 @@ static void verify_call_outs(void)
if(!v->size) if(!v->size)
fatal("Call out array of zero size!\n"); fatal("Call out array of zero size!\n");
if(CALL(e)->prev_arr[0] != CALL(e))
fatal("call_out[%d]->prev_arr[0] is wrong!\n",e);
if(CALL(e)->prev_fun[0] != CALL(e))
fatal("call_out[%d]->prev_fun[0] is wrong!\n",e);
if(CALL(e)->pos != e)
fatal("Call_out->pos is not correct!\n");
if(d_flag>4) if(d_flag>4)
{ {
for(d=e+1;d<num_pending_calls;d++) for(d=e+1;d<num_pending_calls;d++)
if(CALL(e).args == CALL(d).args) if(CALL(e)->args == CALL(d)->args)
fatal("Duplicate call out in heap.\n"); fatal("Duplicate call out in heap.\n");
} }
} }
for(d=0;d<10 && e<call_buffer_size;d++,e++) for(d=0;d<10 && e<call_buffer_size;d++,e++)
CALL(e)=(call_out *)-1;
for(e=0;e<(int)hash_size;e++)
{
call_out *c,**prev;
for(prev=& call_hash[e].arr;(c=*prev);prev=& c->next_arr)
{
if(c->prev_arr != prev)
fatal("c->prev_arr is wrong %p.\n",c);
if(c->pos<0)
fatal("Free call_out in call_out hash table %p.\n",c);
}
for(prev=& call_hash[e].fun;(c=*prev);prev=& c->next_fun)
{ {
CALL(e).caller=(struct object *)1; /* Illegal value */ if(c->prev_fun != prev)
CALL(e).args=(struct array *)1; /* Illegal value */ fatal("c->prev_fun is wrong %p.\n",c);
if(c->pos<0)
fatal("Free call_out in call_out hash table %p.\n",c);
} }
} }
}
static struct callback *verify_call_out_callback=0; static struct callback *verify_call_out_callback=0;
void do_verify_call_outs(struct callback *foo, void *x, void *y) void do_verify_call_outs(struct callback *foo, void *x, void *y)
{ {
...@@ -124,7 +196,6 @@ void do_verify_call_outs(struct callback *foo, void *x, void *y) ...@@ -124,7 +196,6 @@ void do_verify_call_outs(struct callback *foo, void *x, void *y)
#endif #endif
static void adjust_down(int pos) static void adjust_down(int pos)
{ {
while(1) while(1)
...@@ -185,46 +256,106 @@ static struct array * new_call_out(int num_arg,struct svalue *argp) ...@@ -185,46 +256,106 @@ static struct array * new_call_out(int num_arg,struct svalue *argp)
int e,c; int e,c;
call_out *new,**p,**pos; call_out *new,**p,**pos;
struct array *args; struct array *args;
unsigned long hval;
PROTECT_CALL_OUTS(); PROTECT_CALL_OUTS();
if(num_pending_calls==call_buffer_size) if(num_pending_calls==call_buffer_size)
{ {
/* here we need to allocate space for more pointers */ /* here we need to allocate space for more pointers */
call_out *new_buffer; call_out **new_buffer;
if(!call_buffer) if(!call_buffer)
{ {
call_buffer_size=128; call_buffer_size=128;
call_buffer=(call_out *)xalloc(sizeof(call_out)*call_buffer_size); call_buffer=(call_out **)xalloc(sizeof(call_out *)*call_buffer_size);
if(!call_buffer) return 0; if(!call_buffer) return 0;
num_pending_calls=0; num_pending_calls=0;
hash_size=hashprimes[hash_order];
call_hash=(struct hash_ent *)xalloc(sizeof(struct hash_ent)*hash_size);
MEMSET(call_hash, 0, sizeof(struct hash_ent)*hash_size);
}else{ }else{
new_buffer=(call_out *)realloc((char *)call_buffer, sizeof(call_out)*call_buffer_size*2); struct hash_ent *new_hash;
int e;
new_buffer=(call_out **)realloc((char *)call_buffer, sizeof(call_out *)*call_buffer_size*2);
if(!new_buffer) if(!new_buffer)
error("Not enough memory for another call_out\n"); error("Not enough memory for another call_out\n");
call_buffer_size*=2; call_buffer_size*=2;
call_buffer=new_buffer; call_buffer=new_buffer;
if((new_hash=(struct hash_ent *)malloc(sizeof(struct hash_ent)*
hashprimes[hash_order+1])))
{
free((char *)call_hash);
call_hash=new_hash;
hash_size=hashprimes[++hash_order];
MEMSET(call_hash, 0, sizeof(struct hash_ent)*hash_size);
/* Re-hash */
for(e=0;e<num_pending_calls;e++)
{
call_out *c=CALL(e);
hval=(unsigned long)c->args;
hval%=hash_size;
if((c->next_arr=call_hash[hval].arr))
c->next_arr->prev_arr=&c->next_arr;
c->prev_arr=&call_hash[hval].arr;
call_hash[hval].arr=c;
hval=hash_svalue(c->args->item);
hval%=hash_size;
if((c->next_fun=call_hash[hval].fun))
c->next_fun->prev_fun=&c->next_fun;
c->prev_fun=&call_hash[hval].fun;
call_hash[hval].fun=c;
}
}
} }
} }
/* time to allocate a new call_out struct */ /* time to allocate a new call_out struct */
f_aggregate(num_arg-1); args=aggregate_array(num_arg-1);
new=&CALL(num_pending_calls); CALL(num_pending_calls)=new=alloc_call_out_s();
new->pos=num_pending_calls;
if(argp[0].type==T_INT)
{ {
hval=(unsigned long)args;
hval%=hash_size;
if((new->next_arr=call_hash[hval].arr))
new->next_arr->prev_arr=&new->next_arr;
new->prev_arr=&call_hash[hval].arr;
call_hash[hval].arr=new;
hval=hash_svalue(args->item);
hval%=hash_size;
if((new->next_fun=call_hash[hval].fun))
new->next_fun->prev_fun=&new->next_fun;
new->prev_fun=&call_hash[hval].fun;
call_hash[hval].fun=new;
}
switch(argp[0].type)
{
case T_INT:
new->tv.tv_sec=argp[0].u.integer; new->tv.tv_sec=argp[0].u.integer;
new->tv.tv_usec=0; new->tv.tv_usec=0;
} break;
else if(argp[0].type == T_FLOAT)
case T_FLOAT:
{ {
FLOAT_TYPE tmp=argp[0].u.float_number; FLOAT_TYPE tmp=argp[0].u.float_number;
new->tv.tv_sec=floor(tmp); new->tv.tv_sec=floor(tmp);
new->tv.tv_usec=(long)(1000000.0 * (tmp - floor(tmp))); new->tv.tv_usec=(long)(1000000.0 * (tmp - floor(tmp)));
break;
} }
else
{ default:
fatal("Bad timeout to new_call_out!\n"); fatal("Bad timeout to new_call_out!\n");
} }
...@@ -245,8 +376,10 @@ static struct array * new_call_out(int num_arg,struct svalue *argp) ...@@ -245,8 +376,10 @@ static struct array * new_call_out(int num_arg,struct svalue *argp)
new->caller=0; new->caller=0;
} }
new->args=args=sp[-1].u.array; new->args=args;
sp -= 2; sp--;
num_pending_calls++; num_pending_calls++;
adjust_up(num_pending_calls-1); adjust_up(num_pending_calls-1);
...@@ -267,6 +400,8 @@ static void count_memory_in_call_outs(struct callback *foo, ...@@ -267,6 +400,8 @@ static void count_memory_in_call_outs(struct callback *foo,
push_text("num_call_outs"); push_text("num_call_outs");
push_int(num_pending_calls); push_int(num_pending_calls);
push_text("call_out_bytes"); push_text("call_out_bytes");
/* FIXME */
push_int(call_buffer_size * sizeof(call_out **)+ push_int(call_buffer_size * sizeof(call_out **)+
num_pending_calls * sizeof(call_out)); num_pending_calls * sizeof(call_out));
} }
...@@ -281,9 +416,9 @@ static void mark_call_outs(struct callback *foo, void *bar, void *gazonk) ...@@ -281,9 +416,9 @@ static void mark_call_outs(struct callback *foo, void *bar, void *gazonk)
int e; int e;
for(e=0;e<num_pending_calls;e++) for(e=0;e<num_pending_calls;e++)
{ {
gc_external_mark(CALL(e).args); gc_external_mark(CALL(e)->args);
if(CALL(e).caller) if(CALL(e)->caller)
gc_external_mark(CALL(e).caller); gc_external_mark(CALL(e)->caller);
} }
} }
#endif #endif
...@@ -337,19 +472,21 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg) ...@@ -337,19 +472,21 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
{ {
tmp=(time_t)TIME(0); tmp=(time_t)TIME(0);
while(num_pending_calls && while(num_pending_calls &&
my_timercmp(&CALL(0).tv,<=,&current_time)) my_timercmp(&CALL(0)->tv,<=,&current_time))
{ {
/* unlink call out */ /* unlink call out */
call_out c; call_out c,*cc;
PROTECT_CALL_OUTS(); PROTECT_CALL_OUTS();
c=CALL(0); cc=CALL(0);
if(--num_pending_calls) if(--num_pending_calls)
{ {
CALL(0)=CALL(num_pending_calls); MOVECALL(0,num_pending_calls);
adjust_down(0); adjust_down(0);
} }
UNPROTECT_CALL_OUTS(); UNPROTECT_CALL_OUTS();
c=*cc;
free_call_out_s(cc);
if(c.caller) free_object(c.caller); if(c.caller) free_object(c.caller);
...@@ -372,9 +509,9 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg) ...@@ -372,9 +509,9 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
{ {
if(num_pending_calls) if(num_pending_calls)
{ {
if(my_timercmp(& CALL(0).tv, < , &next_timeout)) if(my_timercmp(& CALL(0)->tv, < , &next_timeout))
{ {
next_timeout = CALL(0).tv; next_timeout = CALL(0)->tv;
} }
}else{ }else{
if(call_out_backend_callback) if(call_out_backend_callback)
...@@ -391,17 +528,55 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg) ...@@ -391,17 +528,55 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
static int find_call_out(struct svalue *fun) static int find_call_out(struct svalue *fun)
{ {
#if 0
int e; int e;
if(fun->type == T_ARRAY) if(fun->type == T_ARRAY)
for(e=0;e<num_pending_calls;e++) for(e=0;e<num_pending_calls;e++)
if(CALL(e).args == fun->u.array) if(CALL(e)->args == fun->u.array)
return e; return e;
for(e=0;e<num_pending_calls;e++) for(e=0;e<num_pending_calls;e++)
if(is_eq(fun, ITEM(CALL(e).args))) if(is_eq(fun, ITEM(CALL(e)->args)))
return e; return e;
#else
unsigned long hval;
call_out *c;
if(!num_pending_calls) return -1;
if(fun->type == T_ARRAY)
{
hval=(unsigned long)fun->u.array;
hval%=hash_size;
for(c=call_hash[hval].arr;c;c=c->next_arr)
{
if(c->args == fun->u.array)
{
#ifdef DEBUG
if(CALL(c->pos) != c)
fatal("Call_out->pos not correct!\n");
#endif
return c->pos;
}
}
}
hval=hash_svalue(fun);
hval%=hash_size;
for(c=call_hash[hval].fun;c;c=c->next_fun)
{
if(is_eq(fun, ITEM(c->args)))
{
#ifdef DEBUG
if(CALL(c->pos) != c)
fatal("Call_out->pos not correct!\n");
#endif
return c->pos;
}
}
#endif
return -1; return -1;
} }
...@@ -429,7 +604,7 @@ void f_find_call_out(INT32 args) ...@@ -429,7 +604,7 @@ void f_find_call_out(INT32 args)
sp->u.integer=-1; sp->u.integer=-1;
sp++; sp++;
}else{ }else{
push_int(CALL(e).tv.tv_sec - current_time.tv_sec); push_int(CALL(e)->tv.tv_sec - current_time.tv_sec);
} }
UNPROTECT_CALL_OUTS(); UNPROTECT_CALL_OUTS();
verify_call_outs(); verify_call_outs();
...@@ -438,20 +613,22 @@ void f_find_call_out(INT32 args) ...@@ -438,20 +613,22 @@ void f_find_call_out(INT32 args)
void f_remove_call_out(INT32 args) void f_remove_call_out(INT32 args)
{ {
int e; int e;
verify_call_outs();
PROTECT_CALL_OUTS(); PROTECT_CALL_OUTS();
verify_call_outs();
e=find_call_out(sp-args); e=find_call_out(sp-args);
verify_call_outs();
if(e!=-1) if(e!=-1)
{ {
pop_n_elems(args); pop_n_elems(args);
push_int(CALL(e).tv.tv_sec - current_time.tv_sec); push_int(CALL(e)->tv.tv_sec - current_time.tv_sec);
free_array(CALL(e).args); free_array(CALL(e)->args);
if(CALL(e).caller) if(CALL(e)->caller)
free_object(CALL(e).caller); free_object(CALL(e)->caller);
free_call_out_s(CALL(e));
--num_pending_calls; --num_pending_calls;
if(e!=num_pending_calls) if(e!=num_pending_calls)
{ {
CALL(e)=CALL(num_pending_calls); MOVECALL(e,num_pending_calls);
adjust(e); adjust(e);
} }
}else{ }else{
...@@ -461,8 +638,8 @@ void f_remove_call_out(INT32 args) ...@@ -461,8 +638,8 @@ void f_remove_call_out(INT32 args)
sp->u.integer=-1; sp->u.integer=-1;
sp++; sp++;
} }
UNPROTECT_CALL_OUTS();
verify_call_outs(); verify_call_outs();
UNPROTECT_CALL_OUTS();
} }
/* return an array containing info about all call outs: /* return an array containing info about all call outs:
...@@ -479,22 +656,22 @@ struct array *get_all_call_outs(void) ...@@ -479,22 +656,22 @@ struct array *get_all_call_outs(void)
for(e=0;e<num_pending_calls;e++) for(e=0;e<num_pending_calls;e++)
{ {
struct array *v; struct array *v;
v=allocate_array_no_init(CALL(e).args->size+2, 0); v=allocate_array_no_init(CALL(e)->args->size+2, 0);
ITEM(v)[0].type=T_INT; ITEM(v)[0].type=T_INT;
ITEM(v)[0].subtype=NUMBER_NUMBER; ITEM(v)[0].subtype=NUMBER_NUMBER;
ITEM(v)[0].u.integer=CALL(e).tv.tv_sec - current_time.tv_sec; ITEM(v)[0].u.integer=CALL(e)->tv.tv_sec - current_time.tv_sec;
if(CALL(e).caller) if(CALL(e)->caller)
{ {
ITEM(v)[1].type=T_OBJECT; ITEM(v)[1].type=T_OBJECT;
add_ref(ITEM(v)[1].u.object=CALL(e).caller); add_ref(ITEM(v)[1].u.object=CALL(e)->caller);
}else{ }else{
ITEM(v)[1].type=T_INT; ITEM(v)[1].type=T_INT;
ITEM(v)[1].subtype=NUMBER_NUMBER; ITEM(v)[1].subtype=NUMBER_NUMBER;
ITEM(v)[1].u.integer=0; ITEM(v)[1].u.integer=0;
} }
assign_svalues_no_free(ITEM(v)+2,ITEM(CALL(e).args),CALL(e).args->size,BIT_MIXED); assign_svalues_no_free(ITEM(v)+2,ITEM(CALL(e)->args),CALL(e)->args->size,BIT_MIXED);
ITEM(ret)[e].type=T_ARRAY; ITEM(ret)[e].type=T_ARRAY;
ITEM(ret)[e].u.array=v; ITEM(ret)[e].u.array=v;
...@@ -515,10 +692,13 @@ void free_all_call_outs(void) ...@@ -515,10 +692,13 @@ void free_all_call_outs(void)
verify_call_outs(); verify_call_outs();
for(e=0;e<num_pending_calls;e++) for(e=0;e<num_pending_calls;e++)
{ {
free_array(CALL(e).args); free_array(CALL(e)->args);
if(CALL(e).caller) free_object(CALL(e).caller); if(CALL(e)->caller) free_object(CALL(e)->caller);
free_call_out_s(CALL(e));
} }
if(call_buffer) free((char*)call_buffer); if(call_buffer) free((char*)call_buffer);
if(call_hash) free((char*)call_hash);
free_all_call_out_s_blocks();
num_pending_calls=0; num_pending_calls=0;
call_buffer=NULL; call_buffer=NULL;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment