ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
/*---------------------------------------------------------------------------
 * Gamedriver - Dump object statistics.
 *
 *---------------------------------------------------------------------------
 * Function to compute the memory usage of objects and dump their
 * statistics.
 *---------------------------------------------------------------------------
 */

#include "driver.h"
#include "typedefs.h"

#include <stdio.h>

#define USES_SVALUE_STRLEN
#include "dumpstat.h"
#include "array.h"
#include "closure.h"
#include "exec.h"
#include "filestat.h"
#include "instrs.h"
#include "mapping.h"
#include "object.h"
#include "ptrtable.h"
#include "simulate.h"
#include "smalloc.h"
#include "xalloc.h"
#include "svalue.h"

/*-------------------------------------------------------------------------*/

static size_t svalue_size(svalue_t *, mp_int *); /* forward */

/* Auxiliary structure for counting a mapping */

struct svalue_size_locals
{
    mp_uint composite;   /* Return: total composite memory usage of all elmts */
    mp_uint total;       /* Return: total memory usage of all elmts */
    int     num_values;  /* Passed: width of the mapping */
};

/*-------------------------------------------------------------------------*/

static struct pointer_table *ptable;
  /* The pointer_table to register all arrays and mappings.
   */

/*-------------------------------------------------------------------------*/
static void
svalue_size_map_filter (svalue_t *key, svalue_t *values, void *extra)

/* Called for all keys in a mapping, it counts the size of the values
 * and returns the total in extra->num_values.
 */

{
    struct svalue_size_locals *locals;
    mp_int total;
    int i;

    locals = (struct svalue_size_locals*)extra;
    locals->composite += svalue_size(key, &total);
    locals->total += total;
    for(i = locals->num_values; --i >= 0; )
    {
        locals->composite += svalue_size(values++, &total) + sizeof(svalue_t);
        locals->total += total + sizeof(svalue_t);
    }
}

/*-------------------------------------------------------------------------*/
static size_t
svalue_size (svalue_t *v, mp_int * pTotal)

/* Compute the memory usage of *<v> (modified to reflect data sharing),
 * calling svalue_size() recursively if necessary, and return it.
 * The size of *v itself is not included.
 * *<pUnshared> and *<pShared> are set to the total unshared and shared
 * datasize.
 */

{
    mp_int i, composite, total, overhead;

    assert_stack_gap();

    *pTotal = 0;

    total = overhead = composite = 0;

    switch(v->type)
    {
    case T_OBJECT:
    case T_NUMBER:
    case T_FLOAT:
        return 0;

    case T_STRING:
        /* Include some malloc overhead. */
        if (v->x.string_type == STRING_SHARED)
        {
            *pTotal = (strlen(v->u.string) + sizeof(StrRefCount) + 3*sizeof(char*)) &
              (~(sizeof(char *) - 1));
            return *pTotal / *((StrRefCount*)(v->u.string - sizeof(StrRefCount)));
        }
        else
        {
            *pTotal = (svalue_strlen(v) + 2*sizeof(char *)) & (~(sizeof(char *) - 1));
            return *pTotal;
        }
        break;

    case T_SYMBOL:
        *pTotal = (strlen(v->u.string) + sizeof(StrRefCount) + 3*sizeof(char*)) &
          (~(sizeof(char *) - 1));
        return *pTotal / *((StrRefCount*)(v->u.string - sizeof(StrRefCount)));

    case T_MAPPING:
    {
        struct svalue_size_locals locals;
        struct condensed_mapping *cm;

        if (NULL == register_pointer(ptable, v->u.map) ) return 0;

        cm = v->u.map->condensed;
        overhead = (mp_uint)(cm->string_size + cm->misc_size);
        locals.total = 0;
        locals.composite = 0;
        locals.num_values = v->u.map->num_values;
        walk_mapping(v->u.map, svalue_size_map_filter, &locals);
        if (v->u.map->hash)
            overhead +=
              sizeof(struct hash_mapping) +
                v->u.map->hash->mask * sizeof(struct map_chain *) +
                  v->u.map->hash->used *
                    (sizeof (struct map_chain) - sizeof(svalue_t));

        *pTotal = locals.total + overhead;
        return (overhead + locals.composite) / v->u.map->ref;
    }

    case T_POINTER:
    case T_QUOTED_ARRAY:
    {
        if (v->u.vec == &null_vector) return 0;
        if (NULL == register_pointer(ptable, v->u.vec) ) return 0;
#ifdef MALLOC_smalloc
        overhead = malloced_size(v->u.vec) * sizeof(p_int);
#else
        overhead = sizeof *v->u.vec - sizeof v->u.vec->item +
          sizeof(svalue_t) * v->u.vec->size + sizeof(char *);
#endif
        for (i=0; i < (mp_int)VEC_SIZE(v->u.vec); i++) {
            composite += svalue_size(&v->u.vec->item[i], &total);
            *pTotal += total;
        }
        *pTotal += overhead;
        return (overhead + composite) / v->u.vec->ref;
    }

    case T_CLOSURE:
    {
        int num_values;
        svalue_t *svp;
        lambda_t *l;

        if (!CLOSURE_MALLOCED(v->x.closure_type)) return 0;
        if (!CLOSURE_REFERENCES_CODE(v->x.closure_type))
        {
            /* CLOSURE_LFUN || CLOSURE_IDENTIFIER || CLOSURE_PRELIMINARY */
            composite = sizeof *v->u.lambda + sizeof(char *);
            *pTotal = composite;
            return composite / v->u.lambda->ref;
        }
        /* CLOSURE_LAMBDA */
        composite = overhead = 0;
        l = v->u.lambda;
        if (v->x.closure_type == CLOSURE_BOUND_LAMBDA)
        {
            total = sizeof *l - sizeof l->function + sizeof l->function.lambda;
            *pTotal += total;
            composite += total / l->ref;
            l = l->function.lambda;
        }
        num_values = EXTRACT_UCHAR(&l->function.code[0]);
        if (num_values == 0xff)
            num_values = ((svalue_t *)l)[-0xff].u.number;
        svp = (svalue_t *)l - num_values;
        if (NULL == register_pointer(ptable, svp)) return 0;
#ifdef MALLOC_smalloc
        overhead = malloced_size(svp) * sizeof(p_int);
#else
        overhead = sizeof(svalue_t) * num_values + sizeof (char *);
        {
            bytecode_p p = &l->function.code[2];
            do {
                ++p;
                switch(GET_CODE(p)) {
                  case F_RETURN:
                  case F_RETURN0:
                    break;
                  default:
                    continue;
                }
                break;
            } while (1);
            overhead +=    (p - (bytecode_p)l + (sizeof(bytecode_p) - 1))
                        & ~(sizeof(bytecode_p) - 1);
        }
#endif

        while (--num_values >= 0)
        {
            composite += svalue_size(svp++, &total);
            *pTotal += total;
        }

        *pTotal += overhead;
        return (overhead + composite) / l->ref;
    }

    default:
        fatal("Illegal type: %d\n", v->type);
    }

    /*NOTREACHED*/
    return 0;
}

/*-------------------------------------------------------------------------*/
mp_int
data_size (object_t *ob, mp_int * pTotal)

/* Compute the memory usage (modified to reflect shared data use)
 * of the data held by object <ob> and return it.
 * If the object is swapped out or has no variables, return 0.
 *
 * If <pTotal> is given, *<pTotal> is set to the raw datasize.
 */

{
    mp_int total = sizeof(p_int); /* smalloc overhead */
    int i;
    svalue_t *svp;

    if (pTotal != NULL)
        *pTotal = 0;

    if (ob->flags & O_SWAPPED || !(i = ob->prog->num_variables) )
        return 0;
    ptable = new_pointer_table();
    if (!ptable)
        error("(dumpstat) Out of memory for new pointer table.\n");
    for (svp = ob->variables; --i >= 0; svp++)
    {
        mp_int tmp;
        total += svalue_size(svp, &tmp) + sizeof (svalue_t);
        if (pTotal != NULL)
            *pTotal += tmp + sizeof(svalue_t);
    }
    free_pointer_table(ptable);
    return total;
} /* data_size() */

/*-------------------------------------------------------------------------*/
mp_int
program_string_size (program_t *prog, mp_int * pOverhead, mp_int * pData)

/* Compute the composite data size of all strings in program <prog>
 * which must be swapped in.
 * Set *<pOverhead> to the size of the overhead in the program structure,
 * and *<pData> to the raw data size of the strings.
 */

{
    int i;
    mp_int rc, data;

    rc = data = 0;

    for (i = prog->num_strings; i--; )
    {
        char * str = prog->strings[i];
        mp_int size;

        size = (strlen(str) + sizeof(StrRefCount) + 3*sizeof(char*)) &
               (~(sizeof(char *) - 1));
        data += size;
        rc += size / *((StrRefCount*)(str - sizeof(StrRefCount)));
    }

    *pOverhead = prog->num_strings * sizeof(char *);
    *pData = data;
    return rc;
} /* program_string_size() */

/*-------------------------------------------------------------------------*/
Bool
dumpstat(char *fname)

/* This function dumps statistics about all listed objects into the file
 * $MUDLIB/<fname>. It is called by the command parser or from debug_info.
 * Return TRUE on success, FALSE if <fname> can't be written.
 */

{
    FILE *f;
    object_t *ob;

    static char *swapstrings[] =
        {"", "PROG SWAPPED", "VAR SWAPPED", "SWAPPED", };

    fname = check_valid_path(fname, current_object, "objdump", MY_TRUE);
    if (!fname)
        return MY_FALSE;
    f = fopen(fname, "w");
    if (!f)
        return MY_FALSE;
    FCOUNT_WRITE(fname);

    for (ob = obj_list; ob; ob = ob->next_all)
    {
        mp_int compsize, totalsize, overhead;
#ifdef DEBUG
        if (ob->flags & O_DESTRUCTED) /* TODO: Can't happen */
            continue;
#endif
        compsize = data_size(ob, &totalsize);

        if (!O_PROG_SWAPPED(ob)
         && (ob->prog->ref == 1 || !(ob->flags & (O_CLONE|O_REPLACED))))
        {
            overhead = ob->prog->total_size;
        }
        else
        {
            overhead = 0;
        }

        overhead += sizeof (object_t);

        fprintf(f, "%-20s %5ld (%5ld) ref %2ld %s %s "
                 , ob->name
                 , compsize + overhead, totalsize + overhead
                 , ob->ref
                 , ob->flags & O_HEART_BEAT ? "HB" : "  "
                 , ob->super ? ob->super->name : "--"
        );
        if (ob->gigaticks)
            fprintf(f, " (%lu%09lu)", ob->gigaticks, ob->ticks);
        else
            fprintf(f, " (%lu)", ob->ticks);
        fprintf(f, " %s\n",
                swapstrings[(O_PROG_SWAPPED(ob)?1:0) | (O_VAR_SWAPPED(ob)?2:0)]
        );
    }
    fclose(f);
    return MY_TRUE;
} /* dumpstat() */

/*-------------------------------------------------------------------------*/
Bool
dumpstat_dest(char *fname)

/* this function dumps statistics about all destructed objects into the file
 * $MUDLIB/<fname>. It is called by the commandparser and by debug_info().
 * Return TRUE on success, FALSE if <fname> can't be written.
 */

{
    FILE *f;
    object_t *ob;

    fname = check_valid_path(fname, current_object, "objdump", MY_TRUE);
    if (!fname)
        return MY_FALSE;
    f = fopen(fname, "w");
    if (!f)
        return MY_FALSE;
    FCOUNT_WRITE(fname);

    for (ob = newly_destructed_objs; ob; ob = ob->next_all)
    {
#ifdef DEBUG
        if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */
            continue;
#endif
        fprintf(f, "%-20s ref %2ld NEW\n"
                 , ob->name
                 , ob->ref
        );
    }

    for (ob = destructed_objs; ob; ob = ob->next_all)
    {
#ifdef DEBUG
        if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */
            continue;
#endif
        fprintf(f, "%-20s ref %2ld\n"
                 , ob->name
                 , ob->ref
        );
    }
    fclose(f);
    return MY_TRUE;
} /* dumpstat_dest() */

/***************************************************************************/