Simplified profiling system and enabled it by default. This should be safe, because it no longer depends on dladdr() and friends (which don't work reliably anywhere), and instead expects the profiling modules to register their own symbol table.

main
theraven 16 years ago
parent 6cac2816cc
commit 6459292a40

@ -2,6 +2,7 @@
#include <stdint.h>
#include <dlfcn.h>
#define PROFILE
__thread id objc_msg_sender;
static struct objc_slot nil_slot = { Nil, Nil, "", 1, (IMP)nil_method };
@ -80,6 +81,7 @@ Slot_t (*objc_plane_lookup)(id *receiver, SEL op, id sender) =
*/
Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
{
//fprintf(stderr, "Looking up slot %s\n", sel_get_name(selector));
// Returning a nil slot allows the caller to cache the lookup for nil too,
// although this is not particularly useful because the nil method can be
// inlined trivially.
@ -110,12 +112,6 @@ Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
}
#ifdef PROFILE
/**
* When profiling, the runtime writes out two files, one containing tuples of
* call sites and associated information, the other containing symbolic
* information for resolving these. The loggedValues sparse array is used to prevent duplication of
*/
static struct sarray *loggedValues;
/**
* Mutex used to protect non-thread-safe parts of the profiling subsystem.
*/
@ -129,35 +125,46 @@ FILE *profileSymbols;
*/
FILE *profileData;
static char *objc_profile_resolve_symbol_null(void *addr) { return NULL; }
/**
* Hook allowing JIT'd functions to be resolved. Takes an address as an
* argument and returns the symbol name.
*/
char *(*objc_profile_resolve_symbol)(void *addr) =
objc_profile_resolve_symbol_null;
// Don't enable profiling in the default build (yet)
struct profile_info
{
const char *module;
int32_t callsite;
IMP method;
Class cls;
};
static void __objc_profile_init(void)
{
INIT_LOCK(profileLock);
loggedValues = sarray_new(128, 0);
profileSymbols = fopen("objc_profile.symbols", "a");
profileData = fopen("objc_profile.data", "a");
// Write markers indicating a new run.
fprintf(profileSymbols, "=== NEW TRACE ===\n");
struct profile_info profile_data = { 0, 0, 0, 0};
struct profile_info profile_data = { 0, 0, 0 };
fwrite(&profile_data, sizeof(profile_data), 1, profileData);
}
void objc_profile_write_symbols(char **symbols)
{
if (NULL == profileData)
{
LOCK(__objc_runtime_mutex);
if (NULL == profileData)
{
__objc_profile_init();
}
UNLOCK(__objc_runtime_mutex);
}
LOCK(&profileLock);
while(*symbols)
{
char *address = *(symbols++);
char *symbol = *(symbols++);
fprintf(profileSymbols, "%zx %s\n", (size_t)address, symbol);
}
UNLOCK(&profileLock);
fflush(profileSymbols);
}
/**
* Profiling version of the slot lookup. This takes a unique ID for the module
* and the callsite as extra arguments. The type of the receiver and the
@ -170,60 +177,19 @@ Slot_t objc_msg_lookup_profile(id *receiver, SEL selector, id sender,
{
// Initialize the logging lazily. This prevents us from wasting any memory
// when we are not profiling.
if (NULL == loggedValues)
if (NULL == profileData)
{
LOCK(__objc_runtime_mutex);
if (NULL == loggedValues)
if (NULL == profileData)
{
__objc_profile_init();
}
UNLOCK(__objc_runtime_mutex);
}
// Look up the class if the receiver is not nil
Class cls = Nil;
if (nil != *receiver)
{
cls = (*receiver)->class_pointer;
if (!sarray_get_safe(loggedValues, (size_t)cls))
{
LOCK(&profileLock);
if (!sarray_get_safe(loggedValues, (size_t)cls))
{
fprintf(profileSymbols, "%zx %s\n", (size_t)cls, cls->name);
}
UNLOCK(&profileLock);
}
}
Slot_t slot = objc_msg_lookup_sender(receiver, selector, sender);
IMP method = (IMP)0;
if (0 != slot->version)
{
method = slot->method;
if (!sarray_get_safe(loggedValues, (size_t)method))
{
Dl_info info;
const char *symbolName;
if (dladdr((void*)method, &info))
{
symbolName = info.dli_sname;
}
else
{
symbolName = objc_profile_resolve_symbol((void*)method);
}
if (NULL != symbolName)
{
LOCK(&profileLock);
if (!sarray_get_safe(loggedValues, (size_t)method))
{
fprintf(profileSymbols, "%zx %s\n", (size_t)method, symbolName);
}
UNLOCK(&profileLock);
sarray_at_put_safe(loggedValues, (size_t)method, (void*)1);
}
}
}
struct profile_info profile_data = { module, callsite, method, cls };
IMP method = slot->method;
struct profile_info profile_data = { module, callsite, method };
fwrite(&profile_data, sizeof(profile_data), 1, profileData);
return slot;
}

Loading…
Cancel
Save