Commit 5866470c authored by Pekka Pessi's avatar Pekka Pessi

Updated su_home statistics collection. Fixed bug in su_strlst_t.

Statistics related to "preallocated" homes are now much better.
Added more tests to su_alloc_test().

darcs-hash:20051007073513-65a35-5ef7ace10c48a51f6a670d538d9c1d406d2b8265.gz
parent e8edf1ee
......@@ -470,9 +470,7 @@ void memstats(msg_t *msg, uint32_t msize, context_t *ctx)
options_t *o = ctx->options;
su_home_stat_t hs[1];
hs->hs_size = sizeof(hs);
su_home_get_stats(msg_home(msg), 1, hs);
su_home_get_stats(msg_home(msg), 1, hs, sizeof(hs));
su_home_stat_add(ctx->hs, hs);
if (o->o_histogram) {
......
......@@ -214,8 +214,10 @@ struct su_block_s {
static void su_home_check_blocks(su_block_t const *b);
static void su_home_stats_alloc(su_block_t *sub, void *p, unsigned size);
static void su_home_stats_free(su_block_t *sub, void *p, unsigned size);
static void su_home_stats_alloc(su_block_t *, void *p, void *preload,
unsigned size, int zero);
static void su_home_stats_free(su_block_t *sub, void *p, void *preload,
unsigned size);
static void _su_home_deinit(su_home_t *home);
......@@ -438,7 +440,7 @@ void *sub_alloc(su_home_t *home,
sua->sua_home = zero > 1;
if (sub->sub_stats)
su_home_stats_alloc(sub, data, size);
su_home_stats_alloc(sub, data, preload, size, zero);
}
return data;
......@@ -636,9 +638,14 @@ void su_free(su_home_t *home, void *data)
assert(allocation);
if (su_alloc_check(sub, allocation)) {
void *preloaded = NULL;
/* Is this preloaded data? */
if (su_is_preloaded(sub, data))
preloaded = data;
if (sub->sub_stats)
su_home_stats_free(sub, data, allocation->sua_size);
su_home_stats_free(sub, data, preloaded, allocation->sua_size);
if (allocation->sua_home)
su_home_deinit(data);
......@@ -647,12 +654,11 @@ void su_free(su_home_t *home, void *data)
memset(data, 0xaa, allocation->sua_size);
#endif
/* Is this preloaded data? */
if (su_is_preloaded(sub, data))
data = NULL;
memset(allocation, 0, sizeof (*allocation));
sub->sub_used--;
if (preloaded)
data = NULL;
}
UNLOCK(home);
......@@ -1026,8 +1032,8 @@ void *su_realloc(su_home_t *home, void *data, int size)
ndata = realloc(data, size + MEMCHECK_EXTRA);
if (ndata) {
if (sub->sub_stats) {
su_home_stats_free(sub, data, sua->sua_size);
su_home_stats_alloc(sub, data, size);
su_home_stats_free(sub, data, 0, sua->sua_size);
su_home_stats_alloc(sub, data, 0, size, 1);
}
#if MEMCHECK_EXTRA
......@@ -1053,8 +1059,14 @@ void *su_realloc(su_home_t *home, void *data, int size)
p2 = ALIGN(p2);
if (p2 <= sub->sub_prsize) {
/* Extend/reduce existing preload */
if (sub->sub_stats) {
su_home_stats_free(sub, data, data, sua->sua_size);
su_home_stats_alloc(sub, data, data, size, 0);
}
sub->sub_prused = p2;
sua->sua_size = size;
#if MEMCHECK_EXTRA
memcpy((char *)data + size, &term, sizeof (term));
#endif
......@@ -1064,6 +1076,10 @@ void *su_realloc(su_home_t *home, void *data, int size)
}
else if (size < sua->sua_size) {
/* Reduce existing preload */
if (sub->sub_stats) {
su_home_stats_free(sub, data, data, sua->sua_size);
su_home_stats_alloc(sub, data, data, size, 0);
}
#if MEMCHECK_EXTRA
memcpy((char *)data + size, &term, sizeof (term));
#endif
......@@ -1075,19 +1091,20 @@ void *su_realloc(su_home_t *home, void *data, int size)
ndata = malloc(size + MEMCHECK_EXTRA);
if (ndata) {
if (p == sub->sub_prused)
if (p == sub->sub_prused) {
/* Free preload */
sub->sub_prused = (char *)data - home->suh_blocks->sub_preload;
if (sub->sub_stats)
su_home_stats_free(sub, data, data, sua->sua_size);
}
memcpy(ndata, data, sua->sua_size < size ? sua->sua_size : size);
#if MEMCHECK_EXTRA
memcpy((char *)ndata + size, &term, sizeof (term));
#endif
if (sub->sub_stats) {
su_home_stats_free(sub, data, sua->sua_size);
su_home_stats_alloc(sub, data, size);
}
if (sub->sub_stats)
su_home_stats_alloc(sub, data, 0, size, 1);
memset(sua, 0, sizeof *sua); sub->sub_used--;
......@@ -1247,25 +1264,35 @@ void su_home_init_stats(su_home_t *home)
/** Retrieve statistics from memory home.
*/
void su_home_get_stats(su_home_t *home, int include_clones, su_home_stat_t hs[1])
void su_home_get_stats(su_home_t *home, int include_clones,
su_home_stat_t hs[1],
int size)
{
int size = hs->hs_size;
su_block_t *sub;
if (hs == NULL || size < (sizeof hs->hs_size))
return;
memset(hs, 0, size);
hs->hs_size = size;
sub = MEMLOCK(home);
if (home->suh_blocks && home->suh_blocks->sub_stats) {
int sub_size = home->suh_blocks->sub_stats->hs_size;
if (sub && sub->sub_stats) {
int sub_size = sub->sub_stats->hs_size;
if (sub_size > size)
sub_size = size;
memcpy(hs, home->suh_blocks->sub_stats, sub_size);
sub->sub_stats->hs_preload.hsp_size = sub->sub_prsize;
sub->sub_stats->hs_preload.hsp_used = sub->sub_prused;
memcpy(hs, sub->sub_stats, sub_size);
hs->hs_size = size;
}
UNLOCK(home);
}
static
void su_home_stats_alloc(su_block_t *sub, void *p, unsigned size)
void su_home_stats_alloc(su_block_t *sub, void *p, void *preload,
unsigned size, int zero)
{
su_home_stat_t *hs = sub->sub_stats;
......@@ -1274,24 +1301,36 @@ void su_home_stats_alloc(su_block_t *sub, void *p, unsigned size)
hs->hs_rehash += (sub->sub_n != hs->hs_blocksize);
hs->hs_blocksize = sub->sub_n;
hs->hs_clones += zero > 1;
if (preload) {
hs->hs_allocs.hsa_preload++;
return;
}
hs->hs_allocs.hsa_number++;
hs->hs_allocs.hsa_bytes += size;
hs->hs_allocs.hsa_rbytes += rsize;
if (hs->hs_allocs.hsa_rbytes > hs->hs_allocs.hsa_maxrbytes)
hs->hs_allocs.hsa_maxrbytes = hs->hs_allocs.hsa_rbytes;
hs->hs_blocks.hsb_number++;
hs->hs_blocks.hsb_bytes += size;
hs->hs_blocks.hsb_rbytes += rsize;
}
static
void su_home_stats_free(su_block_t *sub, void *p, unsigned size)
void su_home_stats_free(su_block_t *sub, void *p, void *preload, unsigned size)
{
su_home_stat_t *hs = sub->sub_stats;
unsigned rsize = ALIGN(size);
if (preload) {
hs->hs_frees.hsf_preload++;
return;
}
hs->hs_frees.hsf_number++;
hs->hs_frees.hsf_bytes += size;
hs->hs_frees.hsf_rbytes += rsize;
......
......@@ -82,7 +82,8 @@ SU_DLL void su_home_preload(su_home_t *h, int n, int size);
SU_DLL su_home_t *su_home_auto(void *area, int size);
#define SU_HOME_AUTO_SIZE(n) (((n) + sizeof(su_home_t) - 1)/sizeof(su_home_t))
#define SU_HOME_AUTO_SIZE(n) \
(((n) + sizeof(su_home_t) + 74 * sizeof(void *) - 1)/sizeof(su_home_t))
SU_DLL su_home_t *su_home_incref(su_home_t const *);
......
......@@ -47,7 +47,7 @@ typedef struct su_home_stat_t su_home_stat_t;
SU_DLL void su_home_init_stats(su_home_t *h);
SU_DLL void su_home_get_stats(su_home_t *, int include_clones,
su_home_stat_t *stats);
su_home_stat_t *stats, int statssize);
SU_DLL void su_home_stat_add(su_home_stat_t *total,
su_home_stat_t const *hs);
......@@ -58,17 +58,27 @@ struct su_home_stat_t
unsigned hs_clones; /**< Number of clones */
unsigned hs_rehash; /**< Number of (re)allocations of hash table. */
unsigned hs_blocksize; /**< Current size of hash table */
struct {
unsigned hsp_size; /**< Size of preload area */
unsigned hsp_used; /**< Number of bytes used from preload */
} hs_preload;
struct {
uint64_t hsa_number;
uint64_t hsa_bytes;
uint64_t hsa_rbytes;
uint64_t hsa_maxrbytes;
uint64_t hsa_preload; /**< Number of allocations from preload area */
} hs_allocs;
struct {
uint64_t hsf_number;
uint64_t hsf_bytes;
uint64_t hsf_rbytes;
uint64_t hsf_preload; /**< Number of free()s from preload area */
} hs_frees;
struct {
uint64_t hsb_number;
uint64_t hsb_bytes;
......
......@@ -44,6 +44,7 @@ const char su_alloc_test_c_id[] =
#include <su_alloc.h>
#include <su_strlst.h>
#include <su_alloc_stat.h>
#define TSTFLAGS tstflags
#include <tstdef.h>
......@@ -58,32 +59,6 @@ static int test_strlst(void);
static int test_vectors(void);
static int test_auto(void);
void usage(void)
{
fprintf(stderr, "usage: %s [-v]\n", name);
}
int main(int argc, char *argv[])
{
int retval = 0;
int i;
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else
usage();
}
retval |= test_alloc();
retval |= test_strdupcat();
retval |= test_strlst();
retval |= test_vectors();
retval |= test_auto();
return retval;
}
/** Test tl_list and tl_dup */
int test_alloc(void)
{
......@@ -165,6 +140,31 @@ static int test_strdupcat(void)
END();
}
#include <stdarg.h>
static int test_sprintf(char const *fmt, ...)
{
BEGIN();
su_home_t home[1] = { SU_HOME_INIT(home) };
va_list va;
TEST_S(su_sprintf(home, "foo%s", "bar"), "foobar");
va_start(va, fmt);
TEST_S(su_vsprintf(home, fmt, va), "foo.bar");
TEST_S(su_sprintf(home, "foo%200s", "bar"),
"foo "
" "
" "
" bar");
su_home_deinit(home);
END();
}
static int test_strlst(void)
{
su_home_t home[1] = { SU_HOME_INIT(home) };
......@@ -174,8 +174,16 @@ static int test_strlst(void)
char bar[] = "bar";
char baz[] = "baz";
su_home_stat_t parent[1], kids[2];
BEGIN();
parent->hs_size = (sizeof parent);
kids[0].hs_size = (sizeof kids[0]);
kids[1].hs_size = (sizeof kids[1]);
su_home_init_stats(home);
/* Test API for invalid arguments */
TEST_1(l = su_strlst_create(NULL));
TEST_1(l2 = su_strlst_dup(home, l));
......@@ -215,7 +223,6 @@ static int test_strlst(void)
TEST_1(!su_strlst_get_array(NULL));
TEST_VOID(su_strlst_free_array(NULL, NULL));
TEST_1(l = su_strlst_create(home));
TEST_VOID(su_strlst_free_array(l, NULL));
TEST_S(su_strlst_dup_append(l, "oh"), "oh");
......@@ -224,6 +231,9 @@ static int test_strlst(void)
/* Test functionality */
TEST_1(l = su_strlst_create(home));
su_home_init_stats(su_strlst_home(l));
TEST_S(su_strlst_join(l, home, "bar"), "");
TEST_S(su_strlst_append(l, foo), "foo");
TEST_S(su_strlst_dup_append(l, bar), "bar");
......@@ -240,16 +250,30 @@ static int test_strlst(void)
TEST_1(l2 = su_strlst_dup(su_strlst_home(l), l));
strcpy(foo, "hum"); strcpy(bar, "pah"); strcpy(baz, "hah");
TEST_S(su_strlst_dup_append(l1, "kuik"), "kuik");
TEST_S(su_strlst_dup_append(l2, "uik"), "uik");
TEST_S((s = su_strlst_join(l, home, ".")), "hum.bar.hah");
TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah");
TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz");
TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah.kuik");
TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz.uik");
su_strlst_destroy(l2);
su_home_get_stats(su_strlst_home(l), 0, kids, sizeof kids);
TEST(kids->hs_clones, 2);
TEST(kids->hs_allocs.hsa_number, 3);
TEST(kids->hs_frees.hsf_number, 1);
su_strlst_destroy(l);
TEST_S(s, "hum.bar.hah");
TEST_1(l = su_strlst_create(home));
su_home_init_stats(su_strlst_home(l));
TEST_S(su_strlst_join(l, home, "bar"), "");
TEST_S(su_strlst_append(l, "a"), "a");
TEST_S(su_strlst_append(l, "b"), "b");
......@@ -276,7 +300,12 @@ static int test_strlst(void)
TEST_S((s = su_strlst_join(l, home, "")), "abcdefghijabcdefghij");
su_home_get_stats(su_strlst_home(l), 0, kids + 1, (sizeof kids[1]));
su_home_stat_add(kids, kids + 1);
su_strlst_destroy(l);
su_home_get_stats(home, 1, parent, (sizeof parent));
su_home_check(home);
su_home_deinit(home);
......@@ -486,8 +515,9 @@ static int test_auto(void)
BEGIN();
int i;
su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];
su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)];
char *b = NULL;
su_home_stat_t hs[1];
TEST_1(!su_home_auto(tmphome, sizeof tmphome[0]));
TEST_1(su_home_auto(tmphome, sizeof tmphome));
......@@ -498,13 +528,52 @@ static int test_auto(void)
TEST_VOID(su_home_deinit(tmphome));
TEST_1(su_home_auto(tmphome, sizeof tmphome));
su_home_init_stats(tmphome);
for (i = 1; i < 8192; i++) {
TEST_1(b = su_realloc(tmphome, b, i));
b[i - 1] = 0xaa;
if ((i % 32) == 0)
TEST_1(b = su_realloc(tmphome, b, 1));
}
su_home_get_stats(tmphome, 0, hs, sizeof *hs);
TEST(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number, 8191 + 8191 / 32);
TEST(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number, 8191 + 8191 / 32 - 1);
TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload);
TEST_VOID(su_home_deinit(tmphome));
END();
}
void usage(void)
{
fprintf(stderr, "usage: %s [-v]\n", name);
}
int main(int argc, char *argv[])
{
int retval = 0;
int i;
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else
usage();
}
retval |= test_alloc();
retval |= test_strdupcat();
retval |= test_sprintf("%s.%s", "foo", "bar");
retval |= test_strlst();
retval |= test_vectors();
retval |= test_auto();
return retval;
}
......@@ -148,7 +148,7 @@ su_strlst_t *su_strlst_copy_by(su_home_t *home,
self->sl_total = orig->sl_total;
if (deeply) {
char *s = (char *)(self->sl_list + N);
char *s = (char *)(self->sl_list + self->sl_size);
char *end = s + deepsize;
for (i = 0; i < N; i++) {
self->sl_list[i] = s;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment