
#include "cb_page_info.h"
#include "cb_int_t.h"

#include <malloc.h>
#include <errno.h>
#include <my_assert.h>

#include "vmrss.h"

LONG dfwmalloc_efficiency (void);



long __dfwmalloc_cb_refs (struct dfwmalloc *dfw);
long __dfwmalloc_cb_heap_index_to_chunk_size (int i);
long __dfwmalloc_cb_heap_index_from_pointer (void *u);
struct cb_page_info __dfwmalloc_cb_page_info (int c);
long __dfwmalloc_cb_head_index (int c);


static long get_heap_small (struct dfwmalloc *dfw)
{
    struct dfwmalloc_stats s;
    dfwmalloc_dfwstats (dfw, &s);
    return s.heap_small;
}

static long long get_max_cb_heap (void)
{
    struct dfwmalloc_stats s;
    dfwmalloc_stats (&s);
    return s.max_small_area;
}

static long get_max_cb_size (void)
{
    struct dfwmalloc_stats s;
    dfwmalloc_stats (&s);
    return s.max_cb_size;
}


int n_blocks = 100000;
long total;
int verbose = 2;

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

void efficiency (const char *msg)
{
    int tries = 0;
    double percent = 0.0;
  retry:
    trim ();
    if (tries++ > 100) {
        printf ("Error: %s %ld %2.2f\n", msg, get_os_heap_size (), percent);
        abort ();
    }
    percent = (double) get_os_heap_size () * 1024.0 / (double) (total ? (double) total : 1e99) * 100.0;
    if (verbose > 1)
        printf ("%s %ld %2.2f\n", msg, get_os_heap_size (), percent);
    return;
#if 0
    if (block_size < 40) {
        if (percent > 150.0) {
            usleep (10000);
            goto retry;
        }
    } else if (block_size < 256) {
        if (percent > 130.0) {
            usleep (10000);
            goto retry;
        }
    } else {
        if (percent > 110.0) {
            usleep (10000);
            goto retry;
        }
    }
#endif
}

void test (int interleave, int reverse)
{
    char **r[32];
    int i, j, m, c;
    int n[32];
    struct cb_page_info info;

    total = 0;

    for (c = 0;; c++) {
        info = __dfwmalloc_cb_page_info (c);
        if (info.heap_index == 3)
            break;
//         printf ("%d %d %d %d\n", (int) info.n_blocks, (int) info.heap_index, (int) info.first_block, (int) info.round_up);
    }

    for (m = 2; m < 8; m++) {
        for (i = 0; i < m; i++) {
            info = __dfwmalloc_cb_page_info (c + i);
            n[i] = info.round_up;
            printf ("%d\n", (int) n[i]);
        }
        for (i = 0; i < m; i++) {
            r[i] = (char **) malloc (n_blocks * sizeof (char *));
            total += n_blocks * sizeof (char *);
        }
        for (j = 0; j < n_blocks; j++) {
            for (i = 0; i < m; i++) {
                r[i][j] = (char *) malloc (n[i]);
                if (!r[i][j]) {
                    printf ("%d errno = %d\n", n[i], errno);
                    exit (1);
                }
                r[i][j][0] = 'A';
                total += n[i];
            }
        }

        efficiency ("A:");

        if (interleave == 2) {
            for (j = 0; j < n_blocks - 1; j += 2) {
                for (i = 0; i < m; i++) {
                    free (r[i][j]);
                    total -= n[i];
                }
            }

            efficiency ("A.1:");

            for (j = 0; j < n_blocks - 1; j += 2) {
                for (i = 0; i < m; i++) {
                    r[i][j] = (char *) malloc (n[i]);
                    r[i][j][0] = 'A';
                    total += n[i];
                }
            }

            efficiency ("A.2:");

            if (reverse) {
                for (j = n_blocks - 2; j >= 0; j--) {
                    for (i = 0; i < m; i++) {
                        free (r[i][j]);
                        total -= n[i];
                    }
                }
            } else {
                for (j = 0; j < n_blocks - 1; j++) {
                    for (i = 0; i < m; i++) {
                        free (r[i][j]);
                        total -= n[i];
                    }
                }
            }

        } else if (interleave == 1) {
            for (j = 0; j < n_blocks - 1; j += 2) {
                for (i = 0; i < m; i++) {
                    free (r[i][j]);
                    total -= n[i];
                }
            }

            efficiency ("A.1:");

            for (j = 1; j < n_blocks - 1; j += 2) {
                for (i = 0; i < m; i++) {
                    free (r[i][j]);
                    total -= n[i];
                }
            }

        } else {
            for (j = 0; j < n_blocks - 1; j++) {
                for (i = 0; i < m; i++) {
                    free (r[i][j]);
                    total -= n[i];
                }
            }
        }

        efficiency ("B:");

        for (j = n_blocks - 1; j < n_blocks; j++) {
            for (i = 0; i < m; i++) {
                free (r[i][j]);
                total -= n[i];
            }
        }

        efficiency ("C:");

        for (i = 0; i < m; i++) {
            free (r[i]);
            total -= n_blocks * sizeof (char *);
        }

        efficiency ("D:");

    }
}

void test2 (void)
{
    LONG eff;
    char **r[2];
    int i, j, m, c;
    int n[32];
    struct cb_page_info info;

    total = 0;

    for (c = 0;; c++) {
        info = __dfwmalloc_cb_page_info (c);
        if (info.heap_index == 3)
            break;
//         printf ("%d %d %d %d\n", (int) info.n_blocks, (int) info.heap_index, (int) info.first_block, (int) info.round_up);
    }

    for (i = 0; i < 8; i++) {
        info = __dfwmalloc_cb_page_info (c + i);
        n[i] = info.round_up;
        printf ("%d\n", (int) n[i]);
    }

    for (m = 0; m < 7; m++) {
        r[0] = (char **) malloc (n_blocks * sizeof (char *));
        total += n_blocks * sizeof (char *);
        r[1] = (char **) malloc (n_blocks * sizeof (char *));
        total += n_blocks * sizeof (char *);

        for (j = 0; j < n_blocks; j++) {
            r[0][j] = (char *) malloc (n[m]);
            r[0][j][0] = 'A';
            total += n[m];
        }

        efficiency ("A:");

        for (j = 0; j < n_blocks - 1; j++) {
            free (r[0][j]);
            total -= n[m];
        }

        efficiency ("B:");

        for (j = 0; j < n_blocks; j++) {
            r[1][j] = (char *) malloc (n[m + 1]);
            r[1][j][0] = 'A';
            total += n[m + 1];
        }

        for (j = n_blocks - 1; j < n_blocks; j++) {
            free (r[0][j]);
            total -= n[m];
        }

        efficiency ("C:");

        eff = dfwmalloc_efficiency ();

        printf ("eff=%ld rss=%ld\n", (long) eff / 1024, (long) get_os_heap_size ());

        for (j = 0; j < n_blocks; j++) {
            free (r[1][j]);
            total -= n[m + 1];
        }

        free (r[0]);
        free (r[1]);
        total -= n_blocks * sizeof (char *);
        total -= n_blocks * sizeof (char *);

        printf ("total = %ld\n", (long) total);
        efficiency ("D:");
    }
}

char *p;

void entry (void)
{
    p = (char *) malloc (1);
    *p = '\0';
    test2 ();
}
