Skip to content

Commit

Permalink
Print some memory usage statistics on exit if LIBOBJC_MEMORY_PROFILE is
Browse files Browse the repository at this point in the history
defined.
  • Loading branch information
theraven committed Jan 15, 2013
1 parent 0e90d96 commit 9e93a41
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 10 deletions.
11 changes: 11 additions & 0 deletions loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ void init_selector_tables(void);
void init_trampolines(void);
void objc_send_load_message(Class class);

void log_selector_memory_usage(void);

static void log_memory_stats(void)
{
log_selector_memory_usage();
}

/* Number of threads that are alive. */
int __objc_runtime_threads_alive = 1; /* !T:MUTEX */

Expand Down Expand Up @@ -62,6 +69,10 @@ void __objc_exec_class(struct objc_module_abi_8 *module)
init_arc();
init_trampolines();
first_run = NO;
if (getenv("LIBOBJC_MEMORY_PROFILE"))
{
atexit(log_memory_stats);
}
}

// The runtime mutex is held for the entire duration of a load. It does
Expand Down
4 changes: 4 additions & 0 deletions pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ static mutex_t NAME(_lock);
#define UNLOCK_POOL()
#endif

static int pool_size = 0;
static int pool_allocs = 0;
static inline POOL_TYPE*NAME(_pool_alloc)(void)
{
LOCK_POOL();
pool_allocs++;
if (0 > NAME(_pool_next_index))
{
NAME(_pool) = malloc(PAGE_SIZE);
NAME(_pool_next_index) = POOL_SIZE - 1;
pool_size += PAGE_SIZE;
}
POOL_TYPE* new = &NAME(_pool)[NAME(_pool_next_index)--];
UNLOCK_POOL();
Expand Down
21 changes: 21 additions & 0 deletions sarray2.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,24 @@ PRIVATE void SparseArrayDestroy(SparseArray * sarray)
free(sarray);
}

PRIVATE int SparseArraySize(SparseArray *sarray)
{
int size = 0;
if (sarray->shift == 0)
{
return 256*sizeof(void*) + sizeof(SparseArray);
}
size += 256*sizeof(void*) + sizeof(SparseArray);
for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
{
SparseArray *child = sarray->data[i];
if (child == &EmptyArray ||
child == &EmptyArray8 ||
child == &EmptyArray16)
{
continue;
}
size += SparseArraySize(child);
}
return size;
}
5 changes: 5 additions & 0 deletions sarray2.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,9 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index);
*/
SparseArray *SparseArrayCopy(SparseArray * sarray);

/**
* Returns the total memory usage of a sparse array.
*/
int SparseArraySize(SparseArray *sarray);

#endif //_SARRAY_H_INCLUDED_
44 changes: 34 additions & 10 deletions selector_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
# define TDD(x)
#endif

#define fprintf(...)


// Define the pool allocator for selectors. This is a simple bump-the-pointer
Expand All @@ -43,6 +42,12 @@ static uint32_t selector_count = 1;
*/
PRIVATE SparseArray *selector_list = NULL;

#ifdef DEBUG_SELECTOR_TABLE
#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG_LOG(...)
#endif

// Get the functions for string hashing
#include "string_hash.h"

Expand Down Expand Up @@ -156,7 +161,7 @@ static int selector_identical(const void *k,
const SEL value)
{
SEL key = (SEL)k;
fprintf(stderr, "Comparing %s %s, %s %s\n", sel_getNameNonUnique(key), sel_getNameNonUnique(value), sel_getType_np(key), sel_getType_np(value));
DEBUG_LOG("Comparing %s %s, %s %s\n", sel_getNameNonUnique(key), sel_getNameNonUnique(value), sel_getType_np(key), sel_getType_np(value));
return string_compare(sel_getNameNonUnique(key), sel_getNameNonUnique(value)) &&
selector_types_equal(sel_getType_np(key), sel_getType_np(value));
}
Expand Down Expand Up @@ -226,6 +231,20 @@ static selector_table *sel_table;
*/
mutex_t selector_table_lock;

static int selector_name_copies;

PRIVATE void log_selector_memory_usage(void)
{
fprintf(stderr, "%d bytes in selector name list.\n", SparseArraySize(selector_list));
fprintf(stderr, "%d bytes in selector names.\n", selector_name_copies);
fprintf(stderr, "%d bytes (%d entries) in selector hash table.\n", (int)(sel_table->table_size *
sizeof(struct selector_table_cell_struct)), sel_table->table_size);
fprintf(stderr, "%d selectors registered.\n", selector_count);
fprintf(stderr, "%d hash table cells per selector (%.2f%% full)\n", sel_table->table_size / selector_count, ((float)selector_count) / sel_table->table_size * 100);
}




/**
* Resizes the dtables to ensure that they can store as many selectors as
Expand All @@ -251,7 +270,7 @@ static SEL selector_lookup(const char *name, const char *types)
}
static inline void add_selector_to_table(SEL aSel, int32_t uid, uint32_t idx)
{
//fprintf(stderr, "Sel %s uid: %d, idx: %d, hash: %d\n", sel_getNameNonUnique(aSel), uid, idx, hash_selector(aSel));
DEBUG_LOG("Sel %s uid: %d, idx: %d, hash: %d\n", sel_getNameNonUnique(aSel), uid, idx, hash_selector(aSel));
struct sel_type_list *typeList =
(struct sel_type_list *)selector_pool_alloc();
typeList->value = aSel->name;
Expand All @@ -271,7 +290,7 @@ static inline void register_selector_locked(SEL aSel)
uintptr_t idx = selector_count++;
if (NULL == aSel->types)
{
fprintf(stderr, "Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
DEBUG_LOG("Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
add_selector_to_table(aSel, idx, idx);
objc_resize_dtables(selector_count);
return;
Expand All @@ -283,7 +302,7 @@ static inline void register_selector_locked(SEL aSel)
untyped = selector_pool_alloc();
untyped->name = aSel->name;
untyped->types = 0;
fprintf(stderr, "Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
DEBUG_LOG("Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
add_selector_to_table(untyped, idx, idx);
// If we are in type dependent dispatch mode, the uid for the typed
// and untyped versions will be different
Expand All @@ -296,7 +315,7 @@ static inline void register_selector_locked(SEL aSel)
}
uintptr_t uid = (uintptr_t)untyped->name;
TDD(uid = idx);
fprintf(stderr, "Registering typed selector %d %s %s\n", (int)uid, sel_getNameNonUnique(aSel), sel_getType_np(aSel));
DEBUG_LOG("Registering typed selector %d %s %s\n", (int)uid, sel_getNameNonUnique(aSel), sel_getType_np(aSel));
add_selector_to_table(aSel, uid, idx);

// Add this set of types to the list.
Expand Down Expand Up @@ -340,10 +359,10 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
{
// If an identical selector is already registered, return it.
SEL copy = selector_lookup(aSel->name, aSel->types);
//fprintf(stderr, "Checking if old selector is registered: %d (%d)\n", NULL != copy ? selector_equal(aSel, copy) : 0, ((NULL != copy) && selector_equal(aSel, copy)));
DEBUG_LOG("Checking if old selector is registered: %d (%d)\n", NULL != copy ? selector_equal(aSel, copy) : 0, ((NULL != copy) && selector_equal(aSel, copy)));
if ((NULL != copy) && selector_identical(aSel, copy))
{
//fprintf(stderr, "Not adding new copy\n");
DEBUG_LOG("Not adding new copy\n");
return copy;
}
LOCK_FOR_SCOPE(&selector_table_lock);
Expand All @@ -355,6 +374,7 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
// Create a copy of this selector.
copy = selector_pool_alloc();
copy->name = aSel->name;
copy->types = (NULL == aSel->types) ? NULL : aSel->types;
if (copyArgs)
{
SEL untyped = selector_lookup(aSel->name, 0);
Expand All @@ -365,10 +385,14 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
else
{
copy->name = strdup(aSel->name);
selector_name_copies += strlen(copy->name);
}
if (copy->types != NULL)
{
copy->types = strdup(copy->types);
selector_name_copies += strlen(copy->types);
}
}
copy->types = (NULL == aSel->types) ? NULL :
(copyArgs ? strdup(aSel->types) : aSel->types);
// Try to register the copy as the authoritative version
register_selector_locked(copy);
return copy;
Expand Down

0 comments on commit 9e93a41

Please sign in to comment.