alsalisp memory allocation optimization

- force of reusing alisp objects
  - added auto-garbage-collect mechanism
  - fixed bad garbage-collect (yes, the original code can free "running" lisp program)
  - hctl.lisp test example
    - reduced lisp object memory pool usage from 240kB to 29kB (auto-gc)
    - reduced --''-- from 29kB (auto-gc) to 9kB (manual gc)
FIXME: we need definitely an opminization for the alisp object lookups
       - use bsearch()?
This commit is contained in:
Jaroslav Kysela 2003-08-22 09:41:17 +00:00
parent 06221f86d2
commit 523b1eb92e
3 changed files with 199 additions and 93 deletions

View file

@ -9,6 +9,7 @@
(setq card (aresult card)) (setq card (aresult card))
) )
) )
(unsetq card)
(princ "card_get_index test (SI7018): " (acall 'card_get_index "SI7018") "\n") (princ "card_get_index test (SI7018): " (acall 'card_get_index "SI7018") "\n")
(princ "card_get_index test (ABCD): " (acall 'card_get_index "ABCD") "\n") (princ "card_get_index test (ABCD): " (acall 'card_get_index "ABCD") "\n")
@ -29,6 +30,7 @@
(princ "open failed: " hctl "\n") (princ "open failed: " hctl "\n")
) )
) )
(unsetq hctl)
(setq ctl (acall 'ctl_open 'default nil)) (setq ctl (acall 'ctl_open 'default nil))
(if (= (aerror ctl) 0) (if (= (aerror ctl) 0)
@ -38,6 +40,7 @@
(setq info (aresult (acall 'ctl_card_info ctl))) (setq info (aresult (acall 'ctl_card_info ctl)))
(princ "ctl card info: " info "\n") (princ "ctl card info: " info "\n")
(princ "ctl card info (mixername): " (cdr (assq "mixername" info)) "\n") (princ "ctl card info (mixername): " (cdr (assq "mixername" info)) "\n")
(unsetq info)
(setq hctl (acall 'hctl_open_ctl ctl)) (setq hctl (acall 'hctl_open_ctl ctl))
(if (= (aerror hctl) 0) (if (= (aerror hctl) 0)
(progn (progn
@ -59,6 +62,8 @@
(when (equal (cdr (assq "name" (car (cdr (assq "id" (aresult info)))))) "Master Playback Volume") (when (equal (cdr (assq "name" (car (cdr (assq "id" (aresult info)))))) "Master Playback Volume")
(princ "write Master: " (acall 'hctl_elem_write elem (20 20)) "\n") (princ "write Master: " (acall 'hctl_elem_write elem (20 20)) "\n")
) )
(unsetq info value)
(gc)
(setq elem (acall 'hctl_elem_next elem)) (setq elem (acall 'hctl_elem_next elem))
) )
) )
@ -69,14 +74,17 @@
) )
) )
(progn (progn
(princ "hctl open failed: " ctl "\n") (princ "hctl open failed: " hctl "\n")
(acall 'ctl_close ctl) (acall 'ctl_close ctl)
) )
) )
(unsetq hctl)
) )
(progn (progn
(princ "ctl open failed: " ctl "\n") (princ "ctl open failed: " ctl "\n")
) )
) )
(unsetq ctl)
(&stat-memory) (&stat-memory)
(&dump-memory "memory.dump")

View file

@ -35,7 +35,9 @@
#include "alisp.h" #include "alisp.h"
#include "alisp_local.h" #include "alisp_local.h"
#define ALISP_FREE_OBJ_POOL 1000 /* free objects above this pool */ #define ALISP_FREE_OBJ_POOL 500 /* free objects above this pool */
#define ALISP_AUTO_GC_THRESHOLD 200 /* run automagically garbage-collect when this threshold is reached */
#define ALISP_MAIN_ID "---alisp---main---"
struct alisp_object alsa_lisp_nil; struct alisp_object alsa_lisp_nil;
struct alisp_object alsa_lisp_t; struct alisp_object alsa_lisp_t;
@ -121,6 +123,7 @@ static struct alisp_object * new_object(struct alisp_instance *instance, int typ
nomem(); nomem();
return NULL; return NULL;
} }
++instance->gc_thr_objs;
lisp_debug(instance, "allocating cons %p", p); lisp_debug(instance, "allocating cons %p", p);
} else { } else {
p = instance->free_objs_list; p = instance->free_objs_list;
@ -175,60 +178,6 @@ static void free_objects(struct alisp_instance *instance)
} }
} }
static struct alisp_object * new_integer(struct alisp_instance *instance, long value)
{
struct alisp_object * obj;
obj = new_object(instance, ALISP_OBJ_INTEGER);
if (obj)
obj->value.i = value;
return obj;
}
static struct alisp_object * new_float(struct alisp_instance *instance, double value)
{
struct alisp_object * obj;
obj = new_object(instance, ALISP_OBJ_FLOAT);
if (obj)
obj->value.f = value;
return obj;
}
static struct alisp_object * new_string(struct alisp_instance *instance, const char *str)
{
struct alisp_object * obj;
obj = new_object(instance, ALISP_OBJ_STRING);
if (obj && (obj->value.s = strdup(str)) == NULL) {
nomem();
return NULL;
}
return obj;
}
static struct alisp_object * new_identifier(struct alisp_instance *instance, const char *id)
{
struct alisp_object * obj;
obj = new_object(instance, ALISP_OBJ_IDENTIFIER);
if (obj && (obj->value.id = strdup(id)) == NULL) {
nomem();
return NULL;
}
return obj;
}
static struct alisp_object * new_pointer(struct alisp_instance *instance, const void *ptr)
{
struct alisp_object * obj;
obj = new_object(instance, ALISP_OBJ_POINTER);
if (obj)
obj->value.ptr = ptr;
return obj;
}
static struct alisp_object * search_object_identifier(struct alisp_instance *instance, const char *s) static struct alisp_object * search_object_identifier(struct alisp_instance *instance, const char *s)
{ {
struct alisp_object * p; struct alisp_object * p;
@ -273,6 +222,86 @@ static struct alisp_object * search_object_float(struct alisp_instance *instance
return NULL; return NULL;
} }
static struct alisp_object * search_object_pointer(struct alisp_instance *instance, const void *ptr)
{
struct alisp_object * p;
for (p = instance->used_objs_list; p != NULL; p = p->next)
if (p->type == ALISP_OBJ_POINTER && p->value.ptr == ptr)
return p;
return NULL;
}
static struct alisp_object * new_integer(struct alisp_instance *instance, long value)
{
struct alisp_object * obj;
obj = search_object_integer(instance, value);
if (obj != NULL)
return obj;
obj = new_object(instance, ALISP_OBJ_INTEGER);
if (obj)
obj->value.i = value;
return obj;
}
static struct alisp_object * new_float(struct alisp_instance *instance, double value)
{
struct alisp_object * obj;
obj = search_object_float(instance, value);
if (obj != NULL)
return obj;
obj = new_object(instance, ALISP_OBJ_FLOAT);
if (obj)
obj->value.f = value;
return obj;
}
static struct alisp_object * new_string(struct alisp_instance *instance, const char *str)
{
struct alisp_object * obj;
obj = search_object_string(instance, str);
if (obj != NULL)
return obj;
obj = new_object(instance, ALISP_OBJ_STRING);
if (obj && (obj->value.s = strdup(str)) == NULL) {
nomem();
return NULL;
}
return obj;
}
static struct alisp_object * new_identifier(struct alisp_instance *instance, const char *id)
{
struct alisp_object * obj;
obj = search_object_identifier(instance, id);
if (obj != NULL)
return obj;
obj = new_object(instance, ALISP_OBJ_IDENTIFIER);
if (obj && (obj->value.id = strdup(id)) == NULL) {
nomem();
return NULL;
}
return obj;
}
static struct alisp_object * new_pointer(struct alisp_instance *instance, const void *ptr)
{
struct alisp_object * obj;
obj = search_object_pointer(instance, ptr);
if (obj != NULL)
return obj;
obj = new_object(instance, ALISP_OBJ_POINTER);
if (obj)
obj->value.ptr = ptr;
return obj;
}
void alsa_lisp_init_objects(void) __attribute__ ((constructor)); void alsa_lisp_init_objects(void) __attribute__ ((constructor));
void alsa_lisp_init_objects(void) void alsa_lisp_init_objects(void)
@ -573,28 +602,20 @@ static struct alisp_object * parse_object(struct alisp_instance *instance, int h
else if (!strcmp(instance->token_buffer, "nil")) else if (!strcmp(instance->token_buffer, "nil"))
p = &alsa_lisp_nil; p = &alsa_lisp_nil;
else { else {
if ((p = search_object_identifier(instance, instance->token_buffer)) == NULL) p = new_identifier(instance, instance->token_buffer);
p = new_identifier(instance, instance->token_buffer);
} }
break; break;
case ALISP_INTEGER: { case ALISP_INTEGER: {
long i; p = new_integer(instance, atol(instance->token_buffer));
i = atol(instance->token_buffer);
if ((p = search_object_integer(instance, i)) == NULL)
p = new_integer(instance, i);
break; break;
} }
case ALISP_FLOAT: case ALISP_FLOAT:
case ALISP_FLOATE: { case ALISP_FLOATE: {
double f; p = new_float(instance, atof(instance->token_buffer));
f = atof(instance->token_buffer);
if ((p = search_object_float(instance, f)) == NULL)
p = new_float(instance, f);
break; break;
} }
case ALISP_STRING: case ALISP_STRING:
if ((p = search_object_string(instance, instance->token_buffer)) == NULL) p = new_string(instance, instance->token_buffer);
p = new_string(instance, instance->token_buffer);
break; break;
default: default:
lisp_warn(instance, "%d:%d: unexpected character `%c'", instance->lineno, instance->charno, thistoken); lisp_warn(instance, "%d:%d: unexpected character `%c'", instance->lineno, instance->charno, thistoken);
@ -608,30 +629,47 @@ static struct alisp_object * parse_object(struct alisp_instance *instance, int h
* object manipulation * object manipulation
*/ */
static int set_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value) static struct alisp_object_pair * set_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value)
{ {
struct alisp_object_pair *p; struct alisp_object_pair *p;
if (name->value.id == NULL) if (name->value.id == NULL)
return 0; return NULL;
for (p = instance->setobjs_list; p != NULL; p = p->next) for (p = instance->setobjs_list; p != NULL; p = p->next)
if (p->name->value.id != NULL && if (p->name->value.id != NULL &&
!strcmp(name->value.id, p->name->value.id)) { !strcmp(name->value.id, p->name->value.id)) {
p->value = value; p->value = value;
return 0; return p;
} }
p = (struct alisp_object_pair *)malloc(sizeof(struct alisp_object_pair)); p = (struct alisp_object_pair *)malloc(sizeof(struct alisp_object_pair));
if (p == NULL) { if (p == NULL) {
nomem(); nomem();
return -ENOMEM; return NULL;
} }
p->next = instance->setobjs_list; p->next = instance->setobjs_list;
instance->setobjs_list = p; instance->setobjs_list = p;
p->name = name; p->name = name;
p->value = value; p->value = value;
return 0; return p;
}
static void unset_object(struct alisp_instance *instance, struct alisp_object * name)
{
struct alisp_object_pair *p, *p1;
for (p = instance->setobjs_list, p1 = NULL; p != NULL; p1 = p, p = p->next) {
if (p->name->value.id != NULL &&
!strcmp(name->value.id, p->name->value.id)) {
if (p1)
p1->next = p->next;
else
instance->setobjs_list = p->next;
free(p);
return;
}
}
} }
static struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name) static struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name)
@ -670,6 +708,8 @@ static void dump_objects(struct alisp_instance *instance, const char *fname)
snd_output_printf(out, ")\n"); snd_output_printf(out, ")\n");
continue; continue;
} }
if (!strcmp(p->name->value.id, ALISP_MAIN_ID)) /* internal thing */
continue;
snd_output_printf(out, "(setq %s '", p->name->value.id); snd_output_printf(out, "(setq %s '", p->name->value.id);
princ_object(out, p->value); princ_object(out, p->value);
snd_output_printf(out, ")\n"); snd_output_printf(out, ")\n");
@ -786,6 +826,8 @@ static void do_garbage_collect(struct alisp_instance *instance)
p->next = instance->free_objs_list; p->next = instance->free_objs_list;
instance->free_objs_list = p; instance->free_objs_list = p;
++instance->free_objs; ++instance->free_objs;
if (instance->gc_thr_objs > 0)
instance->gc_thr_objs--;
} else { } else {
free(p); free(p);
} }
@ -801,6 +843,14 @@ static void do_garbage_collect(struct alisp_instance *instance)
instance->used_objs_list = new_used_objs_list; instance->used_objs_list = new_used_objs_list;
} }
static inline void auto_garbage_collect(struct alisp_instance *instance)
{
if (instance->gc_thr_objs >= ALISP_AUTO_GC_THRESHOLD) {
do_garbage_collect(instance);
instance->gc_thr_objs = 0;
}
}
static void garbage_collect(struct alisp_instance *instance) static void garbage_collect(struct alisp_instance *instance)
{ {
if (++instance->gc_id == 255) if (++instance->gc_id == 255)
@ -882,11 +932,10 @@ static struct alisp_object * F_add(struct alisp_instance *instance, struct alisp
} while (p != &alsa_lisp_nil); } while (p != &alsa_lisp_nil);
if (type == ALISP_OBJ_INTEGER) { if (type == ALISP_OBJ_INTEGER) {
p1 = new_integer(instance, v); return new_integer(instance, v);
} else { } else {
p1 = new_float(instance, f); return new_float(instance, f);
} }
return p1;
} }
/* /*
@ -926,11 +975,10 @@ static struct alisp_object * F_sub(struct alisp_instance *instance, struct alisp
} while (p != &alsa_lisp_nil); } while (p != &alsa_lisp_nil);
if (type == ALISP_OBJ_INTEGER) { if (type == ALISP_OBJ_INTEGER) {
p1 = new_integer(instance, v); return new_integer(instance, v);
} else { } else {
p1 = new_object(instance, f); return new_object(instance, f);
} }
return p1;
} }
/* /*
@ -960,12 +1008,10 @@ static struct alisp_object * F_mul(struct alisp_instance *instance, struct alisp
} while (p != &alsa_lisp_nil); } while (p != &alsa_lisp_nil);
if (type == ALISP_OBJ_INTEGER) { if (type == ALISP_OBJ_INTEGER) {
p1 = new_integer(instance, v); return new_integer(instance, v);
} else { } else {
p1 = new_float(instance, f); return new_float(instance, f);
} }
return p1;
} }
/* /*
@ -1018,12 +1064,10 @@ static struct alisp_object * F_div(struct alisp_instance *instance, struct alisp
} while (p != &alsa_lisp_nil); } while (p != &alsa_lisp_nil);
if (type == ALISP_OBJ_INTEGER) { if (type == ALISP_OBJ_INTEGER) {
p1 = new_integer(instance, v); return new_integer(instance, v);
} else { } else {
p1 = new_float(instance, f); return new_float(instance, f);
} }
return p1;
} }
/* /*
@ -1624,12 +1668,23 @@ static struct alisp_object * F_set(struct alisp_instance *instance, struct alisp
if (p1 == &alsa_lisp_nil) { if (p1 == &alsa_lisp_nil) {
lisp_warn(instance, "setting the value of a nil object"); lisp_warn(instance, "setting the value of a nil object");
} else } else
if (set_object(instance, p1, p2)) if (set_object(instance, p1, p2) == NULL)
return NULL; return NULL;
return p2; return p2;
} }
/*
* Syntax: (unset name)
*/
static struct alisp_object * F_unset(struct alisp_instance *instance, struct alisp_object * args)
{
struct alisp_object * p1 = eval(instance, car(args));
unset_object(instance, p1);
return &alsa_lisp_nil;
}
/* /*
* Syntax: (setq name value...) * Syntax: (setq name value...)
* Syntax: (setf name value...) * Syntax: (setf name value...)
@ -1642,7 +1697,7 @@ static struct alisp_object * F_setq(struct alisp_instance *instance, struct alis
do { do {
p1 = car(p); p1 = car(p);
p2 = eval(instance, car(cdr(p))); p2 = eval(instance, car(cdr(p)));
if (set_object(instance, p1, p2)) if (set_object(instance, p1, p2) == NULL)
return NULL; return NULL;
p = cdr(cdr(p)); p = cdr(cdr(p));
} while (p != &alsa_lisp_nil); } while (p != &alsa_lisp_nil);
@ -1650,6 +1705,24 @@ static struct alisp_object * F_setq(struct alisp_instance *instance, struct alis
return p2; return p2;
} }
/*
* Syntax: (unsetq name...)
* Syntax: (unsetf name...)
* `name' is not evalled
*/
static struct alisp_object * F_unsetq(struct alisp_instance *instance, struct alisp_object * args)
{
struct alisp_object * p = args, * p1;
do {
p1 = car(p);
unset_object(instance, p1);
p = cdr(p);
} while (p != &alsa_lisp_nil);
return &alsa_lisp_nil;
}
/* /*
* Syntax: (defun name arglist expr...) * Syntax: (defun name arglist expr...)
* `name' is not evalled * `name' is not evalled
@ -1670,7 +1743,7 @@ static struct alisp_object * F_defun(struct alisp_instance *instance, struct ali
lexpr->value.c.cdr->value.c.car = p2; lexpr->value.c.cdr->value.c.car = p2;
lexpr->value.c.cdr->value.c.cdr = p3; lexpr->value.c.cdr->value.c.cdr = p3;
if (set_object(instance, p1, lexpr)) if (set_object(instance, p1, lexpr) == NULL)
return NULL; return NULL;
} }
@ -1710,7 +1783,7 @@ static struct alisp_object * eval_func(struct alisp_instance *instance, struct a
do { do {
p4 = car(p2); p4 = car(p2);
save_objs[i] = get_object(instance, p4); save_objs[i] = get_object(instance, p4);
if (set_object(instance, p4, eval_objs[i])) if (set_object(instance, p4, eval_objs[i]) == NULL)
return NULL; return NULL;
p2 = cdr(p2); p2 = cdr(p2);
++i; ++i;
@ -1725,7 +1798,7 @@ static struct alisp_object * eval_func(struct alisp_instance *instance, struct a
i = 0; i = 0;
do { do {
p4 = car(p2); p4 = car(p2);
if (set_object(instance, p4, save_objs[i++])) if (set_object(instance, p4, save_objs[i++]) == NULL)
return NULL; return NULL;
p2 = cdr(p2); p2 = cdr(p2);
} while (p2 != &alsa_lisp_nil); } while (p2 != &alsa_lisp_nil);
@ -1976,6 +2049,9 @@ static struct intrinsic intrinsics[] = {
{ "string=", F_equal }, { "string=", F_equal },
{ "string-equal", F_equal }, { "string-equal", F_equal },
{ "unless", F_unless }, { "unless", F_unless },
{ "unset", F_unset },
{ "unsetf", F_unsetq },
{ "unsetq", F_unsetq },
{ "when", F_when }, { "when", F_when },
{ "while", F_while }, { "while", F_while },
}; };
@ -1997,6 +2073,9 @@ static struct alisp_object * eval_cons(struct alisp_instance *instance, struct a
if (!strcmp(p1->value.id, "lambda")) if (!strcmp(p1->value.id, "lambda"))
return p; return p;
auto_garbage_collect(instance);
key.name = p1->value.id; key.name = p1->value.id;
if ((item = bsearch(&key, intrinsics, if ((item = bsearch(&key, intrinsics,
sizeof intrinsics / sizeof intrinsics[0], sizeof intrinsics / sizeof intrinsics[0],
@ -2008,6 +2087,7 @@ static struct alisp_object * eval_cons(struct alisp_instance *instance, struct a
sizeof snd_intrinsics[0], compar)) != NULL) sizeof snd_intrinsics[0], compar)) != NULL)
return item->func(instance, p2); return item->func(instance, p2);
if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil) if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil)
return eval_func(instance, p3, p2); return eval_func(instance, p3, p2);
else else
@ -2044,13 +2124,15 @@ static struct alisp_object * F_eval(struct alisp_instance *instance, struct alis
int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance) int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance)
{ {
struct alisp_instance *instance; struct alisp_instance *instance;
struct alisp_object *p, *p1; struct alisp_object *p, *p1, *omain;
struct alisp_object_pair *pmain;
instance = (struct alisp_instance *)malloc(sizeof(struct alisp_instance)); instance = (struct alisp_instance *)malloc(sizeof(struct alisp_instance));
if (instance == NULL) { if (instance == NULL) {
nomem(); nomem();
return -ENOMEM; return -ENOMEM;
} }
memset(instance, 0, sizeof(struct alisp_instance));
instance->verbose = cfg->verbose && cfg->vout; instance->verbose = cfg->verbose && cfg->vout;
instance->warning = cfg->warning && cfg->wout; instance->warning = cfg->warning && cfg->wout;
instance->debug = cfg->debug && cfg->dout; instance->debug = cfg->debug && cfg->dout;
@ -2064,6 +2146,17 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance)
init_lex(instance); init_lex(instance);
omain = new_identifier(instance, ALISP_MAIN_ID);
if (omain == NULL) {
alsa_lisp_free(instance);
return -ENOMEM;
}
pmain = set_object(instance, omain, &alsa_lisp_t);
if (pmain == NULL) {
alsa_lisp_free(instance);
return -ENOMEM;
}
for (;;) { for (;;) {
if ((p = parse_object(instance, 0)) == NULL) if ((p = parse_object(instance, 0)) == NULL)
break; break;
@ -2072,7 +2165,9 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance)
princ_object(instance->vout, p); princ_object(instance->vout, p);
snd_output_putc(instance->vout, '\n'); snd_output_putc(instance->vout, '\n');
} }
pmain->value = p; /* protect the code tree from garbage-collect */
p1 = eval(instance, p); p1 = eval(instance, p);
pmain->value = &alsa_lisp_t; /* let garbage-collect working */
if (instance->verbose) { if (instance->verbose) {
lisp_verbose(instance, "** result"); lisp_verbose(instance, "** result");
princ_object(instance->vout, p1); princ_object(instance->vout, p1);
@ -2089,6 +2184,8 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance)
} }
} }
unset_object(instance, omain);
done_lex(instance); done_lex(instance);
if (_instance) if (_instance)
*_instance = instance; *_instance = instance;

View file

@ -88,6 +88,7 @@ struct alisp_instance {
long free_objs; long free_objs;
long used_objs; long used_objs;
long max_objs; long max_objs;
long gc_thr_objs;
struct alisp_object *free_objs_list; struct alisp_object *free_objs_list;
struct alisp_object *used_objs_list; struct alisp_object *used_objs_list;
/* set object */ /* set object */