#include <stdio.h> #include "lint.h" #include "interpret.h" #include "object.h" #include "exec.h" #define USES_SVALUE_STRLEN #include "smalloc.h" #include "lang.h" #include "instrs.h" #if defined(AMIGA) #include "hosts/amiga/ixfile.h" #endif /* * Write statistics about objects on file. */ #ifdef IMPROVED_DUMPSTAT /* Quick and dirty referenced-table management. ** The table in object.c is unfortunately single threaded. */ struct trecord { struct trecord *next; void *item; }; static struct trecord *global_table[256]; static void init_gtable() { int i; for (i = 256; i--;) global_table[i] = NULL; } static void free_gtable() { int i; struct trecord *ptr; for (i = 256; i--;) while ((ptr = global_table[i]) != NULL) { global_table[i] = ptr->next; xfree(ptr); } } static int is_refd (void *item) { int key; long pointer; struct trecord *this; pointer = (long)item; key = pointer ^ pointer >> 16; key ^= key >> 8; key &= 0xff; this = global_table[key]; while (this != NULL) { if (this->item == item) return 1; this = this->next; } this = xalloc(sizeof (struct trecord)); if (!this) return 0; this->item = item; this->next = global_table[key]; global_table[key] = this; return 0; } #define SETTOTAL(x) *rtotal = (x); #define INCTOTAL(x) *rtotal += (x); #define REFTOTAL(i,x) if (!is_refd((void *)(i))) *rtotal = (x); #define REFITOTAL(i,x) if (!is_refd((void *)(i))) *rtotal += (x); #else #define SETTOTAL(x) #define INCTOTAL(x) #define REFTOTAL(i,x) #define REFITOTAL(i,x) #endif #ifdef MAPPINGS #ifdef IMPROVED_DUMPSTAT static int svalue_size PROT((struct svalue *, int *)); #else static int svalue_size PROT((struct svalue *)); #endif struct svalue_size_locals { mp_int total; #ifdef IMPROVED_DUMPSTAT mp_int rtotal; #endif int num_values; }; void svalue_size_map_filter(key, values, extra) struct svalue *key; struct svalue *values; char *extra; { struct svalue_size_locals *locals; int i; locals = (struct svalue_size_locals*)extra; #ifdef IMPROVED_DUMPSTAT { int tmp; locals->total += svalue_size(key, &tmp); locals->rtotal += tmp; for(i = locals->num_values; --i >= 0; ) { locals->total += svalue_size(values++, &tmp) + sizeof(struct svalue); locals->rtotal += tmp + sizeof(struct svalue); } } #else locals->total += svalue_size(key); for(i = locals->num_values; --i >= 0; ) { locals->total += svalue_size(values++) + sizeof(struct svalue); } #endif } #endif extern struct object *obj_list; #ifndef IMPROVED_DUMPSTAT static int svalue_size(v) struct svalue *v; #else static int svalue_size(v, rtotal) struct svalue *v; int *rtotal; #endif { mp_int i, total; SETTOTAL(0) switch(v->type) { case T_OBJECT: case T_NUMBER: #ifdef FLOATS case T_FLOAT: #endif return 0; case T_STRING: /* Include some malloc overhead. */ if (v->x.string_type == STRING_SHARED) { REFTOTAL(v->u.string, strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) & ~(sizeof(char *) - 1)) return strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) & ~(sizeof(char *) - 1); } SETTOTAL(svalue_strlen(v) + 2*sizeof(char *) & ~(sizeof(char *) - 1)) return svalue_strlen(v) + 2*sizeof(char *) & ~(sizeof(char *) - 1); case T_SYMBOL: REFTOTAL(v->u.string, strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) & ~(sizeof(char *) - 1)) return strlen(v->u.string) + sizeof(short) + 3*sizeof(char*) & ~(sizeof(char *) - 1); #ifdef MAPPINGS case T_MAPPING: { extern int register_pointer PROT((char *)); extern void walk_mapping PROT(( struct mapping *, void (*)(struct svalue *, struct svalue *, char *), char * )); struct svalue_size_locals locals; struct condensed_mapping *cm; if (register_pointer( (char *)(v->u.map) ) ) return 0; cm = v->u.map->condensed; locals.total = cm->string_size + cm->misc_size; #ifdef IMPROVED_DUMPSTAT locals.rtotal = cm->string_size + cm->misc_size; #endif locals.num_values = v->u.map->num_values; walk_mapping(v->u.map, svalue_size_map_filter, (char *)&locals); if (v->u.map->hash) locals.total += sizeof(struct hash_mapping) + v->u.map->hash->mask * sizeof(struct map_chain *) + v->u.map->hash->used * (sizeof (struct map_chain) - sizeof(struct svalue)); #ifdef IMPROVED_DUMPSTAT if (!is_refd((void *)(v->u.map))) { if (v->u.map->hash) locals.rtotal += sizeof(struct hash_mapping) + v->u.map->hash->mask * sizeof(struct map_chain *) + v->u.map->hash->used * (sizeof (struct map_chain) - sizeof(struct svalue)); *rtotal += locals.rtotal; } #endif return locals.total; } #endif case T_POINTER: case T_QUOTED_ARRAY: { extern struct vector null_vector; extern int register_pointer PROT((char *)); if (v->u.vec == &null_vector) return 0; if (register_pointer( (char *)(v->u.vec) ) ) return 0; #ifdef MALLOC_smalloc total = malloced_size(v->u.vec) * sizeof(p_int); #else total = sizeof *v->u.vec - sizeof v->u.vec->item + sizeof(struct svalue) * v->u.vec->size + sizeof(char *); #endif #ifdef IMPROVED_DUMPSTAT if (!is_refd((void *)(v->u.vec))) { int tmp; *rtotal = total; for (i=0; i < v->u.vec->size; i++) { total += svalue_size(&v->u.vec->item[i], &tmp); *rtotal += tmp; } } #else for (i=0; i < v->u.vec->size; i++) { total += svalue_size(&v->u.vec->item[i]); } #endif return total; } case T_CLOSURE: { extern int register_pointer PROT((char *)); int num_values; struct svalue *svp; struct lambda *l; if (!CLOSURE_MALLOCED(v->x.closure_type)) return 0; if (!CLOSURE_REFERENCES_CODE(v->x.closure_type)) { /* CLOSURE_LFUN || CLOSURE_IDENTIFIER || CLOSURE_PRELIMINARY */ REFTOTAL(v->u.lambda,sizeof *v->u.lambda + sizeof(char *)) return sizeof *v->u.lambda + sizeof(char *); } /* CLOSURE_LAMBDA */ total = 0; SETTOTAL(0) l = v->u.lambda; if (v->x.closure_type == CLOSURE_BOUND_LAMBDA) { REFTOTAL(l, sizeof *l - sizeof l->function + sizeof l->function.lambda) total += sizeof *l - sizeof l->function + sizeof l->function.lambda; l = l->function.lambda; } num_values = EXTRACT_UCHAR(&l->function.code[0]); if (num_values == 0xff) num_values = ((struct svalue *)l)[-0xff].u.number; svp = (struct svalue *)l - num_values; if (register_pointer( (char *)svp ) ) return 0; #ifdef MALLOC_smalloc total += malloced_size(svp) * sizeof(p_int); REFITOTAL(svp, malloced_size(svp) * sizeof(p_int)) #else total += sizeof(struct svalue) * num_values + sizeof (char *); REFITOTAL(svp, sizeof(struct svalue) * num_values + sizeof (char *)) { char *p = &l->function.code[2]; do { switch(*++p) { case F_RETURN -F_OFFSET: case F_RETURN0-F_OFFSET: break; } } while (1); total += p - (char *)l + (sizeof(char *) - 1) & ~(sizeof(char *) - 1); REFITOTAL(svp, p - (char *)l + (sizeof(char *) - 1) & ~(sizeof(char *) - 1)) } #endif while (--num_values >= 0) { #ifdef IMPROVED_DUMPSTAT int tmp; total += svalue_size(svp, &tmp); REFITOTAL(svp++, tmp); #else total += svalue_size(svp++); #endif } return total; } default: fatal("Illegal type: %d\n", v->type); } /*NOTREACHED*/ #ifdef lint return 0; #endif } #ifdef IMPROVED_DUMPSTAT static mp_int data_size(ob, rtotal) struct object *ob; int *rtotal; #else static mp_int data_size(ob) struct object *ob; #endif { struct pointer_record; extern void init_pointer_table PROT((struct pointer_record **)); extern void free_pointer_table PROT((void)); mp_int total = 0, i; struct pointer_record *pointer_table_space[256]; #ifdef IMPROVED_DUMPSTAT *rtotal = 0; #endif init_pointer_table(pointer_table_space); if (ob->prog) { init_pointer_table(pointer_table_space); for (i = 0; i < ob->prog->num_variables; i++) #ifdef IMPROVED_DUMPSTAT { int tmp; total += svalue_size(&ob->variables[i], &tmp) + sizeof (struct svalue); *rtotal += tmp; } #else total += svalue_size(&ob->variables[i]) + sizeof (struct svalue); #endif } free_pointer_table(); return total; } void dumpstat() { FILE *f; struct object *ob; f = fopen("OBJ_DUMP", "w"); if (f == 0) return; add_message("Dumping to OBJ_DUMP ..."); #ifdef IMPROVED_DUMPSTAT init_gtable(); #endif for (ob = obj_list; ob; ob = ob->next_all) { mp_int tmp; #ifdef IMPROVED_DUMPSTAT mp_int rtotal; #endif if (ob->prog && (ob->prog->ref == 1 || !(ob->flags & O_CLONE))) tmp = ob->prog->total_size; else tmp = 0; #ifdef IMPROVED_DUMPSTAT fprintf(f, "%-20s %5d %5d (%5d) ref %2d %s %s (%ld) %s\n", ob->name, tmp + data_size(ob, &rtotal) + sizeof (struct object), tmp + rtotal + sizeof (struct object), tmp, ob->ref, #else fprintf(f, "%-20s %5ld ref %2d %s %s (%ld) %s\n", ob->name, tmp + data_size(ob) + sizeof (struct object), ob->ref, #endif ob->flags & O_HEART_BEAT ? "HB" : " ", ob->super ? ob->super->name : "--",/*ob->cpu*/ 0L, ob->swap_num >=0 ? "SWAPPED" : ""); } #ifdef IMPROVED_DUMPSTAT free_gtable(); #endif add_message("done.\n"); fclose(f); }