From 3e5284a0da373cc2e83a934af14c90f46cc4f547 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Tue, 28 Jul 2009 00:21:12 +0000 Subject: Keep a record of the amount of memory consumed by a lwc_context. svn path=/trunk/libwapcaplet/; revision=8834 --- include/libwapcaplet/libwapcaplet.h | 5 ++ src/libwapcaplet.c | 26 +++++++- test/basictests.c | 116 ++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) diff --git a/include/libwapcaplet/libwapcaplet.h b/include/libwapcaplet/libwapcaplet.h index 420f8c3..3b0899d 100644 --- a/include/libwapcaplet/libwapcaplet.h +++ b/include/libwapcaplet/libwapcaplet.h @@ -140,4 +140,9 @@ extern size_t lwc_string_length(lwc_string *str); */ extern uint32_t lwc_string_hash_value(lwc_string *str); +/** + * Retrieve the size, in bytes, of internment context \a ctx. + */ +extern size_t lwc_context_size(lwc_context *ctx); + #endif /* libwapcaplet_h_ */ diff --git a/src/libwapcaplet.c b/src/libwapcaplet.c index 87704bd..4996c6f 100644 --- a/src/libwapcaplet.c +++ b/src/libwapcaplet.c @@ -53,6 +53,7 @@ struct lwc_context_s { lwc_string * buckets[NR_BUCKETS]; lwc_refcounter refcnt; bool refweak; + size_t size; }; lwc_error @@ -72,6 +73,7 @@ lwc_create_context(lwc_allocator_fn alloc, void *pw, (*ret)->alloc_pw = pw; (*ret)->refcnt = 1; (*ret)->refweak = true; + (*ret)->size = sizeof(lwc_context); return lwc_error_ok; } @@ -130,6 +132,7 @@ __lwc_context_intern(lwc_context *ctx, lwc_hash h; lwc_hash bucket; lwc_string *str; + size_t required_size; assert(ctx); assert((s != NULL) || (slen == 0)); @@ -151,7 +154,9 @@ __lwc_context_intern(lwc_context *ctx, } /* Add one for the additional NUL. */ - *ret = str = LWC_ALLOC(sizeof(lwc_string) + slen + 1); + required_size = sizeof(lwc_string) + slen + 1; + + *ret = str = LWC_ALLOC(required_size); if (str == NULL) return lwc_error_oom; @@ -161,7 +166,10 @@ __lwc_context_intern(lwc_context *ctx, if (str->next != NULL) str->next->prevptr = &(str->next); ctx->buckets[bucket] = str; - + + /* Keep context size in sync */ + ctx->size += required_size; + str->len = slen; str->hash = h; str->refcnt = 1; @@ -235,7 +243,10 @@ lwc_context_string_unref(lwc_context *ctx, lwc_string *str) if (str->insensitive != NULL && str->refcnt == 0) lwc_context_string_unref(ctx, str->insensitive); - + + /* Reduce context size by appropriate amount (+1 for trailing NUL) */ + ctx->size -= sizeof(lwc_string) + str->len + 1; + #ifndef NDEBUG memset(str, 0xA5, sizeof(*str) + str->len); #endif @@ -353,3 +364,12 @@ lwc_string_hash_value(lwc_string *str) return str->hash; } + +size_t +lwc_context_size(lwc_context *ctx) +{ + assert(ctx); + + return ctx->size; +} + diff --git a/test/basictests.c b/test/basictests.c index 290a56c..cedb0c3 100644 --- a/test/basictests.c +++ b/test/basictests.c @@ -180,6 +180,12 @@ START_TEST (test_lwc_string_hash_value_aborts) } END_TEST +START_TEST (test_lwc_context_size_aborts) +{ + lwc_context_size(NULL); +} +END_TEST + #endif START_TEST (test_lwc_context_creation_ok) @@ -276,6 +282,105 @@ START_TEST (test_lwc_context_intern_twice_same_ok) } END_TEST +START_TEST (test_lwc_context_size_non_zero) +{ + fail_unless(lwc_context_size(shared_ctx) > 0, + "Size of empty context is zero"); +} +END_TEST + +START_TEST (test_lwc_context_size_updated_on_string_intern) +{ + size_t empty_size = lwc_context_size(shared_ctx); + lwc_string *str; + + fail_unless(empty_size > 0, + "Size of empty context is zero"); + + fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, + "Unable to intern a simple string"); + + fail_unless(lwc_context_size(shared_ctx) > empty_size, + "Post-intern context size is same or smaller than empty size"); +} +END_TEST + +START_TEST (test_lwc_context_size_updated_on_string_unref) +{ + size_t empty_size = lwc_context_size(shared_ctx); + lwc_string *str; + + fail_unless(empty_size > 0, + "Size of empty context is zero"); + + fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, + "Unable to intern a simple string"); + + fail_unless(lwc_context_size(shared_ctx) > empty_size, + "Post-intern context size is same or smaller than empty size"); + + lwc_context_string_unref(shared_ctx, str); + + fail_unless(lwc_context_size(shared_ctx) == empty_size, + "Post-unref context size is not the same as empty size"); +} +END_TEST + +START_TEST (test_lwc_context_size_updated_on_substring_intern) +{ + size_t empty_size = lwc_context_size(shared_ctx); + size_t post_intern_size = 0; + lwc_string *str, *str2; + + fail_unless(empty_size > 0, + "Size of empty context is zero"); + + fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, + "Unable to intern a simple string"); + + post_intern_size = lwc_context_size(shared_ctx); + + fail_unless(post_intern_size > empty_size, + "Post-intern context size is same or smaller than empty size"); + + fail_unless(lwc_context_intern_substring(shared_ctx, str, 0, 1, &str2) == lwc_error_ok, + "Failed to intern substring"); + + fail_unless(lwc_context_size(shared_ctx) > post_intern_size, + "Post-substring-intern context size is same or smaller than pre-substring-intern size"); +} +END_TEST + +START_TEST (test_lwc_context_size_updated_on_substring_unref) +{ + size_t empty_size = lwc_context_size(shared_ctx); + size_t post_intern_size = 0; + lwc_string *str, *str2; + + fail_unless(empty_size > 0, + "Size of empty context is zero"); + + fail_unless(lwc_context_intern(shared_ctx, "one", 3, &str) == lwc_error_ok, + "Unable to intern a simple string"); + + post_intern_size = lwc_context_size(shared_ctx); + + fail_unless(post_intern_size > empty_size, + "Post-intern context size is same or smaller than empty size"); + + fail_unless(lwc_context_intern_substring(shared_ctx, str, 0, 1, &str2) == lwc_error_ok, + "Failed to intern substring"); + + fail_unless(lwc_context_size(shared_ctx) > post_intern_size, + "Post-substring-intern context size is same or smaller than pre-substring-intern size"); + + lwc_context_string_unref(shared_ctx, str2); + + fail_unless(lwc_context_size(shared_ctx) == post_intern_size, + "Post-substring-unref size is not the same as pre-substring-intern size"); +} +END_TEST + /**** The next set of tests need a fixture set with some strings ****/ static lwc_string *intern_one = NULL, *intern_two = NULL, *intern_three = NULL; @@ -487,6 +592,9 @@ lwc_basic_suite(SRunner *sr) tcase_add_test_raise_signal(tc_basic, test_lwc_string_hash_value_aborts, SIGABRT); + tcase_add_test_raise_signal(tc_basic, + test_lwc_context_size_aborts, + SIGABRT); #endif tcase_add_test(tc_basic, test_lwc_context_creation_ok); @@ -501,6 +609,14 @@ lwc_basic_suite(SRunner *sr) tcase_add_test(tc_basic, test_lwc_context_intern_ok); tcase_add_test(tc_basic, test_lwc_context_intern_twice_ok); tcase_add_test(tc_basic, test_lwc_context_intern_twice_same_ok); + tcase_add_test(tc_basic, test_lwc_context_size_non_zero); + tcase_add_test(tc_basic, + test_lwc_context_size_updated_on_string_intern); + tcase_add_test(tc_basic, test_lwc_context_size_updated_on_string_unref); + tcase_add_test(tc_basic, + test_lwc_context_size_updated_on_substring_intern); + tcase_add_test(tc_basic, + test_lwc_context_size_updated_on_substring_unref); suite_add_tcase(s, tc_basic); tc_basic = tcase_create("Ops with a filled context"); -- cgit v1.2.3