Add environment variable NS_TRACE_MALLOC_DISABLE_STACKS for disabling the stack-walking part of trace-malloc to improve performance of tinderbox test machines. (Bug 549561) r=bsmedberg a2.0=tests

This commit is contained in:
L. David Baron 2010-08-19 09:37:59 -04:00
parent 4af0a6f409
commit 0104f063dc

View File

@ -65,6 +65,7 @@
#include "nscore.h"
#include "prinit.h"
#include "prthread.h"
#include "plstr.h"
#include "nsStackWalk.h"
#include "nsTraceMallocCallbacks.h"
@ -158,6 +159,11 @@ static char sdlogname[PATH_MAX] = ""; /* filename for shutdown leak log */
*/
static uint32 tracing_enabled = 0;
/*
* Control whether we should log stacks
*/
static uint32 stacks_enabled = 1;
/*
* This lock must be held while manipulating the calltree, the
* allocations table, the log, or the tmstats.
@ -519,6 +525,10 @@ static uint32 filename_serial_generator = 0;
static callsite calltree_root =
{0, 0, LFD_SET_STATIC_INITIALIZER, NULL, NULL, 0, NULL, NULL, NULL};
/* a fake pc for when stacks are disabled; must be different from the
pc in calltree_root */
#define STACK_DISABLED_PC ((void*)1)
/* Basic instrumentation. */
static nsTMStats tmstats = NS_TMSTATS_STATIC_INITIALIZER;
@ -688,24 +698,38 @@ calltree(void **stack, size_t num_stack_entries, tm_thread *t)
* callsite info.
*/
/*
* NS_DescribeCodeAddress can (on Linux) acquire a lock inside
* the shared library loader. Another thread might call malloc
* while holding that lock (when loading a shared library). So
* we have to exit tmlock around this call. For details, see
* https://bugzilla.mozilla.org/show_bug.cgi?id=363334#c3
*
* We could be more efficient by building the nodes in the
* calltree, exiting the monitor once to describe all of them,
* and then filling in the descriptions for any that hadn't been
* described already. But this is easier for now.
*/
TM_EXIT_LOCK(t);
rv = NS_DescribeCodeAddress(pc, &details);
TM_ENTER_LOCK(t);
if (NS_FAILED(rv)) {
tmstats.dladdr_failures++;
goto fail;
if (!stacks_enabled) {
/*
* Fake the necessary information for our single fake stack
* frame.
*/
PL_strncpyz(details.library, "stacks_disabled",
sizeof(details.library));
details.loffset = 0;
details.filename[0] = '\0';
details.lineno = 0;
details.function[0] = '\0';
details.foffset = 0;
} else {
/*
* NS_DescribeCodeAddress can (on Linux) acquire a lock inside
* the shared library loader. Another thread might call malloc
* while holding that lock (when loading a shared library). So
* we have to exit tmlock around this call. For details, see
* https://bugzilla.mozilla.org/show_bug.cgi?id=363334#c3
*
* We could be more efficient by building the nodes in the
* calltree, exiting the monitor once to describe all of them,
* and then filling in the descriptions for any that hadn't been
* described already. But this is easier for now.
*/
TM_EXIT_LOCK(t);
rv = NS_DescribeCodeAddress(pc, &details);
TM_ENTER_LOCK(t);
if (NS_FAILED(rv)) {
tmstats.dladdr_failures++;
goto fail;
}
}
/* Check whether we need to emit a library trace record. */
@ -932,44 +956,62 @@ backtrace(tm_thread *t, int skip, int *immediate_abort)
t->suppress_tracing++;
/*
* NS_StackWalk can (on Windows) acquire a lock the shared library
* loader. Another thread might call malloc while holding that lock
* (when loading a shared library). So we can't be in tmlock during
* this call. For details, see
* https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
*/
if (!stacks_enabled) {
/*
* Create a single fake stack frame so that all the tools get
* data in the correct format.
*/
if (info->size < 1) {
PR_ASSERT(!info->buffer); /* !info->size == !info->buffer */
info->buffer = __libc_malloc(1 * sizeof(void*));
if (!info->buffer)
return NULL;
info->size = 1;
}
/* skip == 0 means |backtrace| should show up, so don't use skip + 1 */
/* NB: this call is repeated below if the buffer is too small */
info->entries = 0;
rv = NS_StackWalk(stack_callback, skip, info);
*immediate_abort = rv == NS_ERROR_UNEXPECTED;
if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
t->suppress_tracing--;
return NULL;
}
info->entries = 1;
info->buffer[0] = STACK_DISABLED_PC;
} else {
/*
* NS_StackWalk can (on Windows) acquire a lock the shared library
* loader. Another thread might call malloc while holding that lock
* (when loading a shared library). So we can't be in tmlock during
* this call. For details, see
* https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
*/
/*
* To avoid allocating in stack_callback (which, on Windows, is
* called on a different thread from the one we're running on here),
* reallocate here if it didn't have a big enough buffer (which
* includes the first call on any thread), and call it again.
*/
if (info->entries > info->size) {
new_stack_buffer_size = 2 * info->entries;
new_stack_buffer = __libc_realloc(info->buffer,
new_stack_buffer_size * sizeof(void*));
if (!new_stack_buffer)
return NULL;
info->buffer = new_stack_buffer;
info->size = new_stack_buffer_size;
/* and call NS_StackWalk again */
/* skip == 0 means |backtrace| should show up, so don't use skip + 1 */
/* NB: this call is repeated below if the buffer is too small */
info->entries = 0;
NS_StackWalk(stack_callback, skip, info);
rv = NS_StackWalk(stack_callback, skip, info);
*immediate_abort = rv == NS_ERROR_UNEXPECTED;
if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
t->suppress_tracing--;
return NULL;
}
PR_ASSERT(info->entries * 2 == new_stack_buffer_size); /* same stack */
/*
* To avoid allocating in stack_callback (which, on Windows, is
* called on a different thread from the one we're running on here),
* reallocate here if it didn't have a big enough buffer (which
* includes the first call on any thread), and call it again.
*/
if (info->entries > info->size) {
new_stack_buffer_size = 2 * info->entries;
new_stack_buffer = __libc_realloc(info->buffer,
new_stack_buffer_size * sizeof(void*));
if (!new_stack_buffer)
return NULL;
info->buffer = new_stack_buffer;
info->size = new_stack_buffer_size;
/* and call NS_StackWalk again */
info->entries = 0;
NS_StackWalk(stack_callback, skip, info);
/* same stack */
PR_ASSERT(info->entries * 2 == new_stack_buffer_size);
}
}
TM_ENTER_LOCK(t);
@ -1300,11 +1342,17 @@ log_header(int logfd)
PR_IMPLEMENT(void)
NS_TraceMallocStartup(int logfd)
{
const char* stack_disable_env;
/* We must be running on the primordial thread. */
PR_ASSERT(tracing_enabled == 0);
PR_ASSERT(logfp == &default_logfile);
tracing_enabled = (logfd >= 0);
/* stacks are disabled if this env var is set to a non-empty value */
stack_disable_env = PR_GetEnv("NS_TRACE_MALLOC_DISABLE_STACKS");
stacks_enabled = !stack_disable_env || !*stack_disable_env;
if (tracing_enabled) {
PR_ASSERT(logfp->simsize == 0); /* didn't overflow startup buffer */