

/* test storage efficiency */

#ifdef __FreeBSD__
void malloc_trim (int);
#else
#include <malloc.h>
#endif
#include <my_assert.h>

#include "vmrss.h"

void dfwmalloc_set_lfv_enablement (int enabled);


int verbose = 0;
long total;
int block_size;
long start_size;

#define HEAP_SZ         (get_os_heap_size() - start_size)

void trim (void)
{
    malloc_trim (0);
}

void check_efficiency (const char *msg)
{
    int tries = 0;
    double percent = 0.0, extra_fudge = 0.0;
#ifdef __FreeBSD__
    extra_fudge = 10.0;
#else
    (void) extra_fudge;
#endif
  retry:
    trim ();
    if (tries++ > 5) {
        printf ("Error: %s %ld %d %2.2f\n", msg, HEAP_SZ, block_size, percent);
        abort ();
    }
    percent = (double) HEAP_SZ * 1024.0 / (double) total *100.0;
    if (verbose > 1)
        printf ("%s %ld %d %2.2f\n", msg, HEAP_SZ, block_size, percent);
#ifdef CHECK_EFFICIENCY
    if (percent > (double) CHECK_EFFICIENCY) {
        usleep (5000);
        goto retry;
    }
#else
    if (block_size < 8) {
        if (percent > 250.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else if (block_size < 24) {
        if (percent > 190.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else if (block_size < 40) {
        if (percent > 180.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else if (block_size < 80) {
        if (percent > 150.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else if (block_size < 256) {
        if (percent > 140.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else if (block_size < 1024) {
        if (percent > 135.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    } else {
        if (percent > 110.0 + extra_fudge) {
            usleep (5000);
            goto retry;
        }
    }
#endif
}

#define KB      ((32 * 1024 * 1024) / block_size)

void simple (int block_size_)
{
    char **u;
    int i;
    block_size = block_size_;
    total = block_size * KB + KB * sizeof (char *);
    if (verbose > 1)
        printf ("A=%ld\n", HEAP_SZ);
    u = (char **) malloc (KB * sizeof (char *));
    memset (u, '\0', KB * sizeof (char *));
    if (verbose > 1)
        printf ("B=%ld\n", HEAP_SZ);
    for (i = 0; i < KB; i++) {
        u[i] = (char *) malloc (block_size);
        u[i][0] = 'A';
        u[i][block_size - 1] = 'Z';
    }
    if (verbose > 1)
        printf ("C=%ld %2.2f\n", HEAP_SZ, (double) HEAP_SZ * 1024.0 / (double) total * 100.0);
    for (i = KB - 1; i >= 0; i--)
        free (u[i]);
    trim ();
    if (verbose > 1)
        printf ("D=%ld\n", HEAP_SZ);
    free (u);
    trim ();
    if (verbose > 1)
        printf ("E=%ld\n", HEAP_SZ);
}

void interleaved (int block_size_)
{
    char **u;
    int i;
    block_size = block_size_;
    total = block_size * KB + KB * sizeof (char *);
    if (verbose > 1)
        printf ("A: %ld\n", HEAP_SZ);
    u = (char **) malloc (KB * sizeof (char *));
    memset (u, '\0', KB * sizeof (char *));
    if (verbose > 1)
        printf ("B: %ld\n", HEAP_SZ);
    for (i = 0; i < KB; i++) {
        u[i] = (char *) malloc (block_size);
        if (!u[i]) {
            perror ("malloc");
            abort ();
        }
        u[i][0] = 'A';
        u[i][block_size - 1] = 'Z';
    }
    trim ();
    check_efficiency ("C:");
    for (i = KB - 1; i >= 0; i -= 2)
        free (u[i]);
    trim ();
    if (verbose > 1)
        printf ("D: %ld\n", HEAP_SZ);

    for (i = KB - 1; i >= 0; i -= 2) {
        u[i] = (char *) malloc (block_size);
        u[i][0] = 'B';
        u[i][block_size - 1] = 'Y';
    }
    trim ();
    check_efficiency ("E:");
    for (i = KB - 1; i >= 0; i--)
        free (u[i]);
    trim ();
    if (verbose > 1)
        printf ("F: %ld\n", HEAP_SZ);

    free (u);
    trim ();
    if (verbose > 1)
        printf ("G: %ld\n", HEAP_SZ);
    if (verbose > 1)
        printf ("\n");
}

void entry (void)
{
    int i;

    dfwmalloc_set_lfv_enablement (0);

    start_size = get_os_heap_size ();

#if 0
    int l[] = { 2, 4, 5, 6 };
    for (i = 0; i < (int) (sizeof (l) / sizeof (l[0])); i++) {
        interleaved (l[i]);
    }
#else
    for (i = 0; i < 400; i++) {
        int u;
        u = random () % 1024 + 3;
        interleaved (u);
        if (!verbose) {
            printf (".");
            fflush (stdout);
        }
    }
#endif
    if (!verbose) {
        printf ("\n");
        fflush (stdout);
    }
}






