- This patch was written in 3 interdependent parts, which are described below - Part 1A: Allow HangStack to contain raw PCs and Module offsets, r=froydnj The HangStack previously consisted of an array of const char* pointers into its backing string buffer, which represented pseudostack entries. With interleaved stacks, it is now possible for the stack to contain raw unresolved program counters (Kind::PC), and module/offset pairs (Kind::MODOFFSET). To do this, we use a discriminated union, and make the backing array use the discriminated union instead of const char*s. The code cannot use mozilla::Variant<const char*, uintptr_t, Module> unfortuantely, as we cannot use the implementation of ParamTraits for Variant in HangStack's ParamTraits implementation. When deserializing a HangStack over IPC, we need to read the string frame entries into the backing string buffer, and generate const char* entries for each of the strings which we read in over IPC. The default implementation of ParamTraits wouldn't give us access to the enclusing HangStack object while deserializing each individual entry, so we couldn't use it. In fact, Entries don't have ParamTraits implemented for them at all, and can only be sent over IPC as part of a HangStack due to this dependency. Part 1B: Remove nsIHangDetails.pseudoStack, replace ProcessedStack w/ new HangStack type, r=froydnj Previously there were two stack objects on each HangDetails object: mStack and mPseudoStack. mStack was a Telemetry::ProcessedStack, while mPseudoStack was a HangStack. After the changes in part 1A, HangStack can now contain all of the information of both the old HangStack and ProcessedStack, so the mPseudoStack field is renamed to mStack, and the old mStack field is removed. This patch also implements the new GetStack getter, which generates the JS data format for the new HangStack type. Part 1C: Collect interleaved stacks w/ ProfilerStackCollector API in ThreadStackHelper, r=froydnj This new API was added by njn in bug 1380286, and provides both pseudostack and native stack entries to the consumer of the API. This patch changes ThreadStackHelper to use this new API instead of the previous one, and use it to collect the frames directly into HangStack objects.
110 lines
3.4 KiB
C++
110 lines
3.4 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozilla_ThreadStackHelper_h
|
|
#define mozilla_ThreadStackHelper_h
|
|
|
|
#include "js/ProfilingStack.h"
|
|
#include "HangDetails.h"
|
|
#include "nsThread.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#if defined(XP_LINUX)
|
|
#include <signal.h>
|
|
#include <semaphore.h>
|
|
#include <sys/types.h>
|
|
#elif defined(XP_WIN)
|
|
#include <windows.h>
|
|
#elif defined(XP_MACOSX)
|
|
#include <mach/mach.h>
|
|
#endif
|
|
|
|
// Support pseudostack and native stack on these platforms.
|
|
#if defined(XP_LINUX) || defined(XP_WIN) || defined(XP_MACOSX)
|
|
# ifdef MOZ_GECKO_PROFILER
|
|
# define MOZ_THREADSTACKHELPER_PSEUDO
|
|
# define MOZ_THREADSTACKHELPER_NATIVE
|
|
# endif
|
|
#endif
|
|
|
|
|
|
// Android x86 builds consistently crash in the Background Hang Reporter. bug
|
|
// 1368520.
|
|
#if defined(__ANDROID__)
|
|
# undef MOZ_THREADSTACKHELPER_PSEUDO
|
|
# undef MOZ_THREADSTACKHELPER_NATIVE
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
|
|
/**
|
|
* ThreadStackHelper is used to retrieve the profiler pseudo-stack of a
|
|
* thread, as an alternative of using the profiler to take a profile.
|
|
* The target thread first declares an ThreadStackHelper instance;
|
|
* then another thread can call ThreadStackHelper::GetStack to retrieve
|
|
* the pseudo-stack of the target thread at that instant.
|
|
*
|
|
* Only non-copying labels are included in the stack, which means labels
|
|
* with custom text and markers are not included.
|
|
*/
|
|
class ThreadStackHelper : public ProfilerStackCollector
|
|
{
|
|
public:
|
|
// When a native stack is gathered, this vector holds the raw program counter
|
|
// values that FramePointerStackWalk will return to us after it walks the
|
|
// stack. When gathering the Telemetry payload, Telemetry will take care of
|
|
// mapping these program counters to proper addresses within modules.
|
|
typedef NativeHangStack NativeStack;
|
|
|
|
private:
|
|
HangStack* mStackToFill;
|
|
Array<char, nsThread::kRunnableNameBufSize>* mRunnableNameBuffer;
|
|
// const PseudoStack* const mPseudoStack;
|
|
size_t mMaxStackSize;
|
|
size_t mMaxBufferSize;
|
|
size_t mDesiredStackSize;
|
|
size_t mDesiredBufferSize;
|
|
|
|
bool PrepareStackBuffer(HangStack& aStack);
|
|
|
|
public:
|
|
/**
|
|
* Create a ThreadStackHelper instance targeting the current thread.
|
|
*/
|
|
ThreadStackHelper();
|
|
|
|
/**
|
|
* Retrieve the current interleaved stack of the thread associated with this ThreadStackHelper.
|
|
*
|
|
* @param aStack HangStack instance to be filled.
|
|
* @param aRunnableName The name of the current runnable on the target thread.
|
|
* @param aStackWalk If true, native stack frames will be collected
|
|
* along with pseudostack frames.
|
|
*/
|
|
void GetStack(HangStack& aStack, nsACString& aRunnableName, bool aStackWalk);
|
|
|
|
protected:
|
|
/**
|
|
* ProfilerStackCollector
|
|
*/
|
|
virtual void SetIsMainThread() override;
|
|
virtual void CollectNativeLeafAddr(void* aAddr) override;
|
|
virtual void CollectJitReturnAddr(void* aAddr) override;
|
|
virtual void CollectWasmFrame(const char* aLabel) override;
|
|
virtual void CollectPseudoEntry(const js::ProfileEntry& aEntry) override;
|
|
|
|
private:
|
|
void TryAppendFrame(mozilla::HangStack::Frame aFrame);
|
|
|
|
// The profiler's unique thread identifier for the target thread.
|
|
int mThreadId;
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_ThreadStackHelper_h
|