diff options
Diffstat (limited to 'Source/JavaScriptCore/tools/CodeProfiling.cpp')
-rw-r--r-- | Source/JavaScriptCore/tools/CodeProfiling.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/tools/CodeProfiling.cpp b/Source/JavaScriptCore/tools/CodeProfiling.cpp new file mode 100644 index 000000000..f236484c9 --- /dev/null +++ b/Source/JavaScriptCore/tools/CodeProfiling.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CodeProfiling.h" + +#include "CodeProfile.h" +#include "MetaAllocator.h" +#include "signal.h" + +namespace JSC { + +volatile CodeProfile* CodeProfiling::s_profileStack = 0; +CodeProfiling::Mode CodeProfiling::s_mode = CodeProfiling::Disabled; +WTF::MetaAllocatorTracker* CodeProfiling::s_tracker = 0; + +#if COMPILER(CLANG) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-noreturn" +#endif + +#if PLATFORM(MAC) && CPU(X86_64) +// Helper function to start & stop the timer. +// Presently we're using the wall-clock timer, since this seems to give the best results. +static void setProfileTimer(unsigned usec) +{ + itimerval timer; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = usec; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = usec; + setitimer(ITIMER_REAL, &timer, 0); +} +#endif + +#if COMPILER(CLANG) +#pragma clang diagnostic pop +#endif + +#if PLATFORM(MAC) && CPU(X86_64) +static void profilingTimer(int, siginfo_t*, void* uap) +{ + mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext; + CodeProfiling::sample(reinterpret_cast<void*>(context->__ss.__rip), + reinterpret_cast<void**>(context->__ss.__rbp)); +} +#endif + +// Callback triggered when the timer is fired. +void CodeProfiling::sample(void* pc, void** framePointer) +{ + CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack); + if (profileStack) + profileStack->sample(pc, framePointer); +} + +void CodeProfiling::notifyAllocator(WTF::MetaAllocator* allocator) +{ + // Check for JSC_CODE_PROFILING. + const char* codeProfilingMode = getenv("JSC_CODE_PROFILING"); + if (!codeProfilingMode) + return; + + // Check for a valid mode, currently "1", "2", or "3". + if (!codeProfilingMode[0] || codeProfilingMode[1]) + return; + switch (*codeProfilingMode) { + case '1': + s_mode = Enabled; + break; + case '2': + s_mode = Verbose; + break; + case '3': + s_mode = VeryVerbose; + break; + default: + return; + } + + ASSERT(enabled()); + ASSERT(!s_tracker); + s_tracker = new WTF::MetaAllocatorTracker(); + allocator->trackAllocations(s_tracker); +} + +void* CodeProfiling::getOwnerUIDForPC(void* address) +{ + if (!s_tracker) + return 0; + WTF::MetaAllocatorHandle* handle = s_tracker->find(address); + if (!handle) + return 0; + return handle->ownerUID(); +} + +void CodeProfiling::begin(const SourceCode& source) +{ + // Push a new CodeProfile onto the stack for each script encountered. + CodeProfile* profileStack = const_cast<CodeProfile*>(s_profileStack); + bool alreadyProfiling = profileStack; + s_profileStack = profileStack = new CodeProfile(source, profileStack); + + // Is the profiler already running - if so, the timer will already be set up. + if (alreadyProfiling) + return; + +#if PLATFORM(MAC) && CPU(X86_64) + // Regsiter a signal handler & itimer. + struct sigaction action; + action.sa_sigaction = reinterpret_cast<void (*)(int, struct __siginfo *, void *)>(profilingTimer); + sigfillset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + sigaction(SIGALRM, &action, 0); + setProfileTimer(100); +#endif +} + +void CodeProfiling::end() +{ + // Pop the current profiler off the stack. + CodeProfile* current = const_cast<CodeProfile*>(s_profileStack); + ASSERT(current); + s_profileStack = current->parent(); + + // Is this the outermost script being profiled? - if not, just return. + // We perform all output of profiles recursively from the outermost script, + // to minimize profiling overhead from skewing results. + if (s_profileStack) + return; + +#if PLATFORM(MAC) && CPU(X86_64) + // Stop profiling + setProfileTimer(0); +#endif + + current->report(); + delete current; +} + +} |