mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 856331 - Make breakpad unwinding runtime switchable. r=jseward
--HG-- extra : rebase_source : 1094beb17115a0d0e4d27eeb848c3932dfe0b2b0
This commit is contained in:
parent
37e2b2a059
commit
8e7e831c1d
@ -156,7 +156,7 @@ void genPseudoBacktraceEntries(/*MODIFIED*/UnwinderThreadBuffer* utb,
|
||||
}
|
||||
|
||||
// RUNS IN SIGHANDLER CONTEXT
|
||||
void BreakpadSampler::Tick(TickSample* sample)
|
||||
void TableTicker::UnwinderTick(TickSample* sample)
|
||||
{
|
||||
if (!sample->threadProfile) {
|
||||
// Platform doesn't support multithread, so use the main thread profile we created
|
||||
|
@ -392,6 +392,15 @@ void doSampleStackTrace(PseudoStack *aStack, ThreadProfile &aProfile, TickSample
|
||||
}
|
||||
|
||||
void TableTicker::Tick(TickSample* sample)
|
||||
{
|
||||
if (HasUnwinderThread()) {
|
||||
UnwinderTick(sample);
|
||||
} else {
|
||||
InplaceTick(sample);
|
||||
}
|
||||
}
|
||||
|
||||
void TableTicker::InplaceTick(TickSample* sample)
|
||||
{
|
||||
ThreadProfile& currThreadProfile = *sample->threadProfile;
|
||||
|
||||
|
@ -32,6 +32,7 @@ class TableTicker: public Sampler {
|
||||
, mPrimaryThreadProfile(nullptr)
|
||||
, mStartTime(TimeStamp::Now())
|
||||
, mSaveRequested(false)
|
||||
, mUnwinderThread(false)
|
||||
{
|
||||
mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
|
||||
|
||||
@ -39,6 +40,7 @@ class TableTicker: public Sampler {
|
||||
mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
|
||||
mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
|
||||
mProfileThreads = true || hasFeature(aFeatures, aFeatureCount, "threads");
|
||||
mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2();
|
||||
mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
|
||||
|
||||
{
|
||||
@ -119,12 +121,17 @@ class TableTicker: public Sampler {
|
||||
virtual JSObject *ToJSObject(JSContext *aCx);
|
||||
JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
|
||||
|
||||
bool HasUnwinderThread() const { return mUnwinderThread; }
|
||||
bool ProfileJS() const { return mProfileJS; }
|
||||
bool ProfileThreads() const { return mProfileThreads; }
|
||||
|
||||
virtual BreakpadSampler* AsBreakpadSampler() { return nullptr; }
|
||||
|
||||
protected:
|
||||
// Called within a signal. This function must be reentrant
|
||||
virtual void UnwinderTick(TickSample* sample);
|
||||
|
||||
// Called within a signal. This function must be reentrant
|
||||
virtual void InplaceTick(TickSample* sample);
|
||||
|
||||
// Not implemented on platforms which do not support backtracing
|
||||
void doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample);
|
||||
|
||||
@ -139,18 +146,6 @@ protected:
|
||||
bool mJankOnly;
|
||||
bool mProfileJS;
|
||||
bool mProfileThreads;
|
||||
};
|
||||
|
||||
class BreakpadSampler: public TableTicker {
|
||||
public:
|
||||
BreakpadSampler(int aInterval, int aEntrySize,
|
||||
const char** aFeatures, uint32_t aFeatureCount)
|
||||
: TableTicker(aInterval, aEntrySize, aFeatures, aFeatureCount)
|
||||
{}
|
||||
|
||||
// Called within a signal. This function must be reentrant
|
||||
virtual void Tick(TickSample* sample);
|
||||
|
||||
virtual BreakpadSampler* AsBreakpadSampler() { return this; }
|
||||
bool mUnwinderThread;
|
||||
};
|
||||
|
||||
|
@ -71,6 +71,10 @@ void uwt__init()
|
||||
{
|
||||
}
|
||||
|
||||
void uwt__stop()
|
||||
{
|
||||
}
|
||||
|
||||
void uwt__deinit()
|
||||
{
|
||||
}
|
||||
@ -153,13 +157,17 @@ void uwt__init()
|
||||
MOZ_ALWAYS_TRUE(r==0);
|
||||
}
|
||||
|
||||
void uwt__deinit()
|
||||
void uwt__stop()
|
||||
{
|
||||
// Shut down the unwinder thread.
|
||||
MOZ_ASSERT(unwind_thr_exit_now == 0);
|
||||
unwind_thr_exit_now = 1;
|
||||
do_MBAR();
|
||||
int r = pthread_join(unwind_thr, NULL); MOZ_ALWAYS_TRUE(r==0);
|
||||
}
|
||||
|
||||
void uwt__deinit()
|
||||
{
|
||||
do_breakpad_unwind_Buffer_free_singletons();
|
||||
}
|
||||
|
||||
@ -817,14 +825,9 @@ static void* unwind_thr_fn(void* exit_nowV)
|
||||
MOZ_ASSERT(buffers);
|
||||
int i;
|
||||
for (i = 0; i < N_UNW_THR_BUFFERS; i++) {
|
||||
/* These calloc-ations are never freed, even when the unwinder
|
||||
thread is shut down. The reason is that sampler threads
|
||||
might still be filling them up even after this thread is shut
|
||||
down. The buffers themselves are not protected by the
|
||||
spinlock, so we have no way to stop them being accessed
|
||||
whilst we free them. It doesn't matter much since they will
|
||||
not be reallocated if a new unwinder thread is restarted
|
||||
later. */
|
||||
/* These calloc-ations are shared between the sampler and the unwinder.
|
||||
* They must be free after both threads have terminated.
|
||||
*/
|
||||
buffers[i] = (UnwinderThreadBuffer*)
|
||||
calloc(sizeof(UnwinderThreadBuffer), 1);
|
||||
MOZ_ASSERT(buffers[i]);
|
||||
@ -872,7 +875,10 @@ static void* unwind_thr_fn(void* exit_nowV)
|
||||
|
||||
while (1) {
|
||||
|
||||
if (*exit_now != 0) break;
|
||||
if (*exit_now != 0) {
|
||||
*exit_now = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
spinLock_acquire(&g_spinLock);
|
||||
|
||||
@ -1528,6 +1534,11 @@ void do_breakpad_unwind_Buffer_free_singletons()
|
||||
delete sModules;
|
||||
sModules = NULL;
|
||||
}
|
||||
|
||||
g_stackLimitsUsed = 0;
|
||||
g_seqNo = 0;
|
||||
free(g_buffers);
|
||||
g_buffers = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -28,6 +28,13 @@ void utb__addEntry(/*MOD*/UnwinderThreadBuffer* utb,
|
||||
void uwt__init();
|
||||
|
||||
// Request the unwinder thread to exit, and wait until it has done so.
|
||||
// This must be called before stopping the profiler because we hold a
|
||||
// reference to the profile which is owned by the profiler.
|
||||
void uwt__stop();
|
||||
|
||||
// Release the unwinder resources. This must be called after profiling
|
||||
// has stop. At this point we know the profiler doesn't hold any buffer
|
||||
// and can safely release any resources.
|
||||
void uwt__deinit();
|
||||
|
||||
// Registers a sampler thread for profiling. Threads must be registered
|
||||
|
@ -121,18 +121,6 @@ static void SetThreadName(const char* name) {
|
||||
|
||||
static void* ThreadEntry(void* arg) {
|
||||
Thread* thread = reinterpret_cast<Thread*>(arg);
|
||||
// This is also initialized by the first argument to pthread_create() but we
|
||||
// don't know which thread will run first (the original thread or the new
|
||||
// one) so we initialize it here too.
|
||||
|
||||
// BEGIN temp hack for SPS v1-vs-v2
|
||||
extern bool sps_version2();
|
||||
if (sps_version2()) {
|
||||
// Register this thread for profiling.
|
||||
int aLocal;
|
||||
uwt__register_thread_for_profiling( &aLocal );
|
||||
}
|
||||
// END temp hack for SPS v1-vs-v2
|
||||
|
||||
thread->thread_ = pthread_self();
|
||||
SetThreadName(thread->name());
|
||||
|
@ -268,27 +268,10 @@ void mozilla_sampler_init()
|
||||
|
||||
Sampler::RegisterCurrentThread("Gecko", stack, true);
|
||||
|
||||
if (sps_version2()) {
|
||||
// Read mode settings from MOZ_PROFILER_MODE and interval
|
||||
// settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
|
||||
// from MOZ_PROFILER_STACK_SCAN.
|
||||
read_profiler_env_vars();
|
||||
|
||||
// Create the unwinder thread. ATM there is only one.
|
||||
uwt__init();
|
||||
|
||||
# if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
|
||||
|| defined(SPS_PLAT_x86_linux) || defined(SPS_PLAT_x86_android) \
|
||||
|| defined(SPS_PLAT_x86_windows) || defined(SPS_PLAT_amd64_windows) /* no idea if windows is correct */
|
||||
// On Linuxes, register this thread (temporarily) for profiling
|
||||
int aLocal;
|
||||
uwt__register_thread_for_profiling( &aLocal );
|
||||
# elif defined(SPS_PLAT_amd64_darwin) || defined(SPS_PLAT_x86_darwin)
|
||||
// Registration is done in platform-macos.cc
|
||||
# else
|
||||
# error "Unknown plat"
|
||||
# endif
|
||||
}
|
||||
// Read mode settings from MOZ_PROFILER_MODE and interval
|
||||
// settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
|
||||
// from MOZ_PROFILER_STACK_SCAN.
|
||||
read_profiler_env_vars();
|
||||
|
||||
// Allow the profiler to be started using signals
|
||||
OS::RegisterStartHandler();
|
||||
@ -333,14 +316,6 @@ void mozilla_sampler_shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
// Shut down and reap the unwinder thread. We have to do this
|
||||
// before stopping the sampler, so as to guarantee that the unwinder
|
||||
// thread doesn't try to access memory that the subsequent call to
|
||||
// mozilla_sampler_stop causes to be freed.
|
||||
if (sps_version2()) {
|
||||
uwt__deinit();
|
||||
}
|
||||
|
||||
profiler_stop();
|
||||
|
||||
Sampler::Shutdown();
|
||||
@ -396,13 +371,24 @@ const char** mozilla_sampler_get_features()
|
||||
{
|
||||
static const char* features[] = {
|
||||
#if defined(MOZ_PROFILING) && defined(HAVE_NATIVE_UNWIND)
|
||||
// Walk the C++ stack.
|
||||
"stackwalk",
|
||||
#endif
|
||||
#if defined(ENABLE_SPS_LEAF_DATA)
|
||||
// Include the C++ leaf node if not stackwalking. DevTools
|
||||
// profiler doesn't want the native addresses.
|
||||
"leaf",
|
||||
#endif
|
||||
#if !defined(SPS_OS_windows)
|
||||
// Use a seperate thread of walking the stack.
|
||||
"unwinder",
|
||||
#endif
|
||||
// Only record samples during periods of bad responsiveness
|
||||
"jank",
|
||||
// Tell the JS engine to emmit pseudostack entries in the
|
||||
// pro/epilogue.
|
||||
"js",
|
||||
// Profile the registered secondary threads.
|
||||
"threads",
|
||||
NULL
|
||||
};
|
||||
@ -432,15 +418,17 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval,
|
||||
profiler_stop();
|
||||
|
||||
TableTicker* t;
|
||||
if (sps_version2()) {
|
||||
t = new BreakpadSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
|
||||
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
|
||||
aFeatures, aFeatureCount);
|
||||
} else {
|
||||
t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
|
||||
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
|
||||
aFeatures, aFeatureCount);
|
||||
t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
|
||||
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
|
||||
aFeatures, aFeatureCount);
|
||||
if (t->HasUnwinderThread()) {
|
||||
int aLocal;
|
||||
uwt__register_thread_for_profiling( &aLocal );
|
||||
|
||||
// Create the unwinder thread. ATM there is only one.
|
||||
uwt__init();
|
||||
}
|
||||
|
||||
tlsTicker.set(t);
|
||||
t->Start();
|
||||
if (t->ProfileJS()) {
|
||||
@ -475,6 +463,15 @@ void mozilla_sampler_stop()
|
||||
}
|
||||
|
||||
bool disableJS = t->ProfileJS();
|
||||
bool unwinderThreader = t->HasUnwinderThread();
|
||||
|
||||
// Shut down and reap the unwinder thread. We have to do this
|
||||
// before stopping the sampler, so as to guarantee that the unwinder
|
||||
// thread doesn't try to access memory that the subsequent call to
|
||||
// mozilla_sampler_stop causes to be freed.
|
||||
if (unwinderThreader) {
|
||||
uwt__stop();
|
||||
}
|
||||
|
||||
t->Stop();
|
||||
delete t;
|
||||
@ -485,6 +482,10 @@ void mozilla_sampler_stop()
|
||||
if (disableJS)
|
||||
stack->disableJSSampling();
|
||||
|
||||
if (unwinderThreader) {
|
||||
uwt__deinit();
|
||||
}
|
||||
|
||||
sIsProfiling = false;
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
|
Loading…
Reference in New Issue
Block a user