Bug 1375299 (part 1) - Reduce usage of MOZ_GECKO_PROFILER. r=mstange.

This patch reduces the differences between builds where the profiler is enabled
and those where the profiler is disabled. It does this by removing numerous
MOZ_GECKO_PROFILER checks.

These changes have the following consequences.

- Various functions and classes are now defined in all builds, and so can be
  used unconditionally: profiler_add_marker(), profiler_set_js_context(),
  profiler_clear_js_context(), profiler_get_pseudo_stack(), AutoProfilerLabel.
  (They are effectively no-ops in non-profiler builds, of course.)

- The no-op versions of PROFILER_* are now gone. The remaining versions are
  almost no-ops when the profiler isn't built.

--HG--
extra : rebase_source : 8fb5e8757600210c2f77865694d25162f0b7698a
This commit is contained in:
Nicholas Nethercote 2017-06-22 06:26:16 +10:00
parent 98273422c7
commit 4b364cf3f3
21 changed files with 74 additions and 138 deletions

View File

@ -1521,12 +1521,13 @@ void
nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
bool aRunInGlobalScope)
{
#ifdef MOZ_GECKO_PROFILER
NS_LossyConvertUTF16toASCII urlCStr(aURL);
PROFILER_LABEL_DYNAMIC("nsMessageManagerScriptExecutor", "LoadScriptInternal",
js::ProfileEntry::Category::OTHER,
urlCStr.get());
#endif
if (profiler_is_active()) {
NS_LossyConvertUTF16toASCII urlCStr(aURL);
PROFILER_LABEL_DYNAMIC("nsMessageManagerScriptExecutor",
"LoadScriptInternal",
js::ProfileEntry::Category::OTHER,
urlCStr.get());
}
if (!mGlobal || !sCachedScripts) {
return;

View File

@ -135,10 +135,8 @@ EvaluationExceptionToNSResult(JSContext* aCx)
nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
JS::Handle<JSObject*> aGlobal)
:
#ifdef MOZ_GECKO_PROFILER
mAutoProfilerLabel("nsJSUtils::ExecutionContext", /* dynamicStr */ nullptr,
__LINE__, js::ProfileEntry::Category::JS),
#endif
mCx(aCx)
, mCompartment(aCx, aGlobal)
, mRetValue(aCx)

View File

@ -68,10 +68,8 @@ public:
// ExecutionContext is used to switch compartment.
class MOZ_STACK_CLASS ExecutionContext {
#ifdef MOZ_GECKO_PROFILER
// Register stack annotations for the Gecko profiler.
mozilla::AutoProfilerLabel mAutoProfilerLabel;
#endif
JSContext* mCx;

View File

@ -1309,8 +1309,6 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
"DOMEvent",
MakeUnique<DOMEventMarkerPayload>(typeStr, phase,
startTime, endTime));
#else
MOZ_CRASH("Gecko Profiler is N/A but profiler_is_active() returned true");
#endif
} else {
rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);

View File

@ -2905,9 +2905,7 @@ WorkerThreadPrimaryRunnable::Run()
}
{
#ifdef MOZ_GECKO_PROFILER
profiler_set_js_context(cx);
#endif
{
JSAutoRequest ar(cx);
@ -2921,9 +2919,7 @@ WorkerThreadPrimaryRunnable::Run()
BackgroundChild::CloseForCurrentThread();
#ifdef MOZ_GECKO_PROFILER
profiler_clear_js_context();
#endif
}
// There may still be runnables on the debugger event queue that hold a

View File

@ -180,9 +180,7 @@ public:
case Work::Type::SHUTDOWN:
DecodePoolImpl::ShutdownThread(thisThread);
#ifdef MOZ_GECKO_PROFILER
profiler_unregister_thread();
#endif // MOZ_GECKO_PROFILER
return NS_OK;

View File

@ -2503,12 +2503,10 @@ nsXPCComponents_Utils::Import(const nsACString& registryLocation,
if (!moduleloader)
return NS_ERROR_FAILURE;
#ifdef MOZ_GECKO_PROFILER
const nsCString& flatLocation = PromiseFlatCString(registryLocation);
PROFILER_LABEL_DYNAMIC("Components.utils", "import",
js::ProfileEntry::Category::OTHER,
flatLocation.get());
#endif
return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval);
}

View File

@ -728,9 +728,7 @@ XPCJSContext::~XPCJSContext()
delete rtPrivate;
JS_SetContextPrivate(Context(), nullptr);
#ifdef MOZ_GECKO_PROFILER
profiler_clear_js_context();
#endif
gTlsContext.set(nullptr);
}
@ -908,9 +906,7 @@ XPCJSContext::Initialize(XPCJSContext* aPrimaryContext)
kStackQuota - kSystemCodeBuffer,
kStackQuota - kSystemCodeBuffer - kTrustedScriptBuffer);
#ifdef MOZ_GECKO_PROFILER
profiler_set_js_context(cx);
#endif
js::SetActivityCallback(cx, ActivityCallback, this);
JS_AddInterruptCallback(cx, InterruptCallback);

View File

@ -4064,7 +4064,6 @@ PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush)
MOZ_ASSERT(NeedFlush(flushType), "Why did we get called?");
#ifdef MOZ_GECKO_PROFILER
static const EnumeratedArray<FlushType,
FlushType::Count,
const char*> flushTypeNames = {
@ -4078,9 +4077,7 @@ PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush)
};
PROFILER_LABEL_DYNAMIC("PresShell", "Flush",
js::ProfileEntry::Category::GRAPHICS,
flushTypeNames[flushType]);
#endif
js::ProfileEntry::Category::GRAPHICS, flushTypeNames[flushType]);
#ifdef ACCESSIBILITY
#ifdef DEBUG
@ -6291,7 +6288,6 @@ PresShell::Paint(nsView* aViewToPaint,
const nsRegion& aDirtyRegion,
uint32_t aFlags)
{
#ifdef MOZ_GECKO_PROFILER
nsIURI* uri = mDocument->GetDocumentURI();
nsIDocument* contentRoot = GetPrimaryContentDocument();
if (contentRoot) {
@ -6300,7 +6296,6 @@ PresShell::Paint(nsView* aViewToPaint,
nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
PROFILER_LABEL_DYNAMIC("PresShell", "Paint",
js::ProfileEntry::Category::GRAPHICS, uriString.get());
#endif
Maybe<js::AutoAssertNoContentJS> nojs;
@ -9205,12 +9200,10 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
}
#ifdef MOZ_GECKO_PROFILER
nsIURI* uri = mDocument->GetDocumentURI();
nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
PROFILER_LABEL_DYNAMIC("PresShell", "DoReflow",
js::ProfileEntry::Category::GRAPHICS, uriString.get());
#endif
nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();

View File

@ -764,13 +764,11 @@ continue_loading:
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
#endif
#ifdef MOZ_GECKO_PROFILER
// A few DLLs such as xul.dll and nss3.dll get loaded before mozglue's
// AutoProfilerLabel is initialized, and this is a no-op in those cases. But
// the vast majority of DLLs do get labelled here.
AutoProfilerLabel label("WindowsDllBlocklist::patched_LdrLoadDll", dllName,
__LINE__);
#endif
#ifdef _M_AMD64
// Prevent the stack walker from suspending this thread when LdrLoadDll

View File

@ -7,8 +7,6 @@
#ifndef mozilla_AutoProfilerLabel_h
#define mozilla_AutoProfilerLabel_h
#ifdef MOZ_GECKO_PROFILER
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/Types.h"
@ -61,6 +59,4 @@ private:
} // namespace mozilla
#endif // MOZ_GECKO_PROFILER
#endif // mozilla_AutoProfilerLabel_h

View File

@ -22,16 +22,12 @@ if CONFIG['OS_ARCH'] == 'WINNT':
]
SOURCES += [
'AutoProfilerLabel.cpp',
'Printf.cpp',
'StackWalk.cpp',
'TimeStamp.cpp',
]
if CONFIG['MOZ_GECKO_PROFILER']:
SOURCES += [
'AutoProfilerLabel.cpp',
]
OS_LIBS += CONFIG['REALTIME_LIBS']
DEFINES['IMPL_MFBT'] = True

View File

@ -2070,7 +2070,6 @@ TelemetryImpl::RecordChromeHang(uint32_t aDuration,
Move(annotations));
}
#if defined(MOZ_GECKO_PROFILER)
void
TelemetryImpl::DoStackCapture(const nsACString& aKey) {
if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
@ -2078,7 +2077,6 @@ TelemetryImpl::DoStackCapture(const nsACString& aKey) {
}
}
#endif
#endif
nsresult
TelemetryImpl::CaptureStack(const nsACString& aKey) {

View File

@ -14,6 +14,10 @@ class SpliceableJSONWriter;
class ThreadInfo;
class UniqueStacks;
namespace mozilla {
class TimeStamp;
}
// ProfilerBacktrace encapsulates a synchronous sample.
class ProfilerBacktrace
{

View File

@ -571,7 +571,7 @@ public:
static bool Init(PSLockRef)
{
bool ok1 = sThreadInfo.init();
bool ok2 = sPseudoStack.init();
bool ok2 = AutoProfilerLabel::sPseudoStack.init();
return ok1 && ok2;
}
@ -588,12 +588,13 @@ public:
// Get only the PseudoStack. Accesses are not guarded by gPSMutex. RacyInfo()
// can also be used to get the PseudoStack, but that is marginally slower
// because it requires an extra pointer indirection.
static PseudoStack* Stack() { return sPseudoStack.get(); }
static PseudoStack* Stack() { return AutoProfilerLabel::sPseudoStack.get(); }
static void SetInfo(PSLockRef, ThreadInfo* aInfo)
{
sThreadInfo.set(aInfo);
sPseudoStack.set(aInfo ? aInfo->RacyInfo().get() : nullptr); // an upcast
AutoProfilerLabel::sPseudoStack.set(
aInfo ? aInfo->RacyInfo().get() : nullptr); // an upcast
}
private:
@ -617,9 +618,8 @@ MOZ_THREAD_LOCAL(ThreadInfo*) TLSInfo::sThreadInfo;
// - We don't want to expose TLSInfo (and ThreadInfo) in GeckoProfiler.h.
//
// This second pointer isn't ideal, but does provide a way to satisfy those
// constraints. TLSInfo manages it, except for the uses in
// AutoProfilerLabel.
MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
// constraints. TLSInfo is responsible for updating it.
MOZ_THREAD_LOCAL(PseudoStack*) AutoProfilerLabel::sPseudoStack;
// The name of the main thread.
static const char* const kMainThreadName = "GeckoMain";
@ -2083,7 +2083,7 @@ PseudoStack*
MozGlueLabelEnter(const char* aLabel, const char* aDynamicString, void* aSp,
uint32_t aLine)
{
PseudoStack* pseudoStack = sPseudoStack.get();
PseudoStack* pseudoStack = AutoProfilerLabel::sPseudoStack.get();
if (pseudoStack) {
pseudoStack->pushCppFrame(aLabel, aDynamicString, aSp, aLine,
js::ProfileEntry::Kind::CPP_NORMAL,

View File

@ -5,8 +5,6 @@
#ifndef PROFILERIOINTERPOSEOBSERVER_H
#define PROFILERIOINTERPOSEOBSERVER_H
#ifdef MOZ_GECKO_PROFILER
#include "mozilla/IOInterposer.h"
#include "nsISupportsImpl.h"
@ -29,6 +27,4 @@ protected:
} // namespace mozilla
#endif // MOZ_GECKO_PROFILER
#endif // PROFILERIOINTERPOSEOBSERVER_H

View File

@ -16,16 +16,30 @@
#ifndef GeckoProfiler_h
#define GeckoProfiler_h
#include <stdint.h>
#include <stdarg.h>
#include <functional>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "js/TypeDecls.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/Sprintf.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/UniquePtr.h"
#include "js/TypeDecls.h"
#include "js/ProfilingStack.h"
#include "nscore.h"
// Make sure that we can use std::min here without the Windows headers messing
// with us.
#ifdef min
# undef min
#endif
class ProfilerBacktrace;
class ProfilerMarkerPayload;
class SpliceableJSONWriter;
namespace mozilla {
@ -39,24 +53,14 @@ enum TracingKind {
TRACING_INTERVAL_END,
};
class ProfilerBacktrace;
struct ProfilerBacktraceDestructor
{
void operator()(ProfilerBacktrace*);
};
using UniqueProfilerBacktrace =
mozilla::UniquePtr<ProfilerBacktrace, ProfilerBacktraceDestructor>;
#if defined(MOZ_GECKO_PROFILER)
// Use these for functions below that must be visible whether the profiler is
// enabled or not. When the profiler is disabled they are static inline
// functions (with a simple return value if they are non-void) that should be
// optimized away during compilation.
#define PROFILER_FUNC(decl, rv) decl;
#define PROFILER_FUNC_VOID(decl) void decl;
#define PROFILER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
#define PROFILER_APPEND_LINE_NUMBER_EXPAND(id, line) \
PROFILER_APPEND_LINE_NUMBER_PASTE(id, line)
@ -118,27 +122,6 @@ using UniqueProfilerBacktrace =
#define PROFILER_MARKER_PAYLOAD(marker_name, payload) \
profiler_add_marker(marker_name, payload)
#else // defined(MOZ_GECKO_PROFILER)
#define PROFILER_FUNC(decl, rv) static inline decl { return rv; }
#define PROFILER_FUNC_VOID(decl) static inline void decl {}
#define PROFILER_LABEL(name_space, info, category) do {} while (0)
#define PROFILER_LABEL_FUNC(category) do {} while (0)
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
do {} while (0)
#define PROFILER_MARKER(marker_name) do {} while (0)
// Note: this is deliberately not defined when MOZ_GECKO_PROFILER is undefined.
// This macro should not be used in that case -- i.e. all uses of this macro
// should be guarded by a MOZ_GECKO_PROFILER check -- because payload creation
// requires allocation, which is something we should not do in builds that
// don't contain the profiler.
//#define PROFILER_MARKER_PAYLOAD(marker_name, payload) /* undefined */
#endif // defined(MOZ_GECKO_PROFILER)
// Higher-order macro containing all the feature info in one place. Define
// |macro| appropriately to extract the relevant parts. Note that the number
// values are used internally only and so can be changed without consequence.
@ -199,7 +182,16 @@ struct ProfilerFeature
#undef DECLARE
};
// These functions are defined whether the profiler is enabled or not.
// When the profiler is disabled functions declared with these macros are
// static inline functions (with a trivial return value if they are non-void)
// that will be optimized away during compilation.
#ifdef MOZ_GECKO_PROFILER
# define PROFILER_FUNC(decl, rv) decl;
# define PROFILER_FUNC_VOID(decl) void decl;
#else
# define PROFILER_FUNC(decl, rv) static inline decl { return rv; }
# define PROFILER_FUNC_VOID(decl) static inline void decl {}
#endif
// Adds a tracing marker to the PseudoStack. A no-op if the profiler is
// inactive or in privacy mode.
@ -257,7 +249,7 @@ PROFILER_FUNC_VOID(profiler_get_backtrace_noalloc(char* aOutput,
size_t aOutputSize))
// Free a ProfilerBacktrace returned by profiler_get_backtrace().
#if !defined(MOZ_GECKO_PROFILER)
#ifndef MOZ_GECKO_PROFILER
inline void
ProfilerBacktraceDestructor::operator()(ProfilerBacktrace* aBacktrace) {}
#endif
@ -384,33 +376,18 @@ PROFILER_FUNC_VOID(profiler_suspend_and_sample_thread(int aThreadId,
const std::function<void(void**, size_t)>& aCallback,
bool aSampleNative = true))
// End of the functions defined whether the profiler is enabled or not.
#if defined(MOZ_GECKO_PROFILER)
#include <stdlib.h>
#include <signal.h>
#include "js/ProfilingStack.h"
#include "mozilla/Sprintf.h"
#include "mozilla/ThreadLocal.h"
#include "nscore.h"
// Make sure that we can use std::min here without the Windows headers messing with us.
#ifdef min
# undef min
#endif
class ProfilerMarkerPayload;
// This exists purely for AutoProfilerLabel. See the comment on the
// definition in platform.cpp for details.
extern MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
// Adds a marker to the PseudoStack. A no-op if the profiler is inactive or in
// privacy mode.
void profiler_add_marker(const char* aMarkerName);
void profiler_add_marker(const char* aMarkerName,
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
PROFILER_FUNC_VOID(profiler_add_marker(const char* aMarkerName))
PROFILER_FUNC_VOID(profiler_add_marker(const char* aMarkerName,
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload))
// Get the current thread's PseudoStack.
PROFILER_FUNC(PseudoStack* profiler_get_pseudo_stack(), nullptr)
// Set and clear the current thread's JSContext.
PROFILER_FUNC_VOID(profiler_set_js_context(JSContext* aCx))
PROFILER_FUNC_VOID(profiler_clear_js_context())
#if !defined(ARCH_ARMV6)
# define PROFILER_DEFAULT_ENTRIES 1000000
@ -426,7 +403,8 @@ namespace mozilla {
// are stack-allocated, and so exist within a thread, and are thus bounded by
// the lifetime of the thread, which ensures that the references held can't be
// used after the PseudoStack is destroyed.
class MOZ_RAII AutoProfilerLabel {
class MOZ_RAII AutoProfilerLabel
{
public:
AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
uint32_t aLine, js::ProfileEntry::Category aCategory
@ -436,40 +414,40 @@ public:
// This function runs both on and off the main thread.
#ifdef MOZ_GECKO_PROFILER
mPseudoStack = sPseudoStack.get();
if (mPseudoStack) {
mPseudoStack->pushCppFrame(aLabel, aDynamicString, this, aLine,
js::ProfileEntry::Kind::CPP_NORMAL, aCategory);
}
#endif
}
~AutoProfilerLabel()
{
// This function runs both on and off the main thread.
#ifdef MOZ_GECKO_PROFILER
if (mPseudoStack) {
mPseudoStack->pop();
}
#endif
}
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
#ifdef MOZ_GECKO_PROFILER
// We save a PseudoStack pointer in the ctor so we don't have to redo the TLS
// lookup in the dtor.
PseudoStack* mPseudoStack;
public:
// See the comment on the definition in platform.cpp for details about this.
static MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
#endif
};
} // namespace mozilla
PseudoStack* profiler_get_pseudo_stack();
void profiler_set_js_context(JSContext* aCx);
void profiler_clear_js_context();
#endif // defined(MOZ_GECKO_PROFILER)
namespace mozilla {
class MOZ_RAII AutoProfilerInit
{
public:

View File

@ -581,13 +581,11 @@ TEST(GeckoProfiler, PseudoStack)
ASSERT_TRUE(profiler_get_backtrace());
}
#if defined(MOZ_GECKO_PROFILER)
AutoProfilerLabel label1("A", nullptr, 888,
js::ProfileEntry::Category::STORAGE);
AutoProfilerLabel label2("A", dynamic.get(), 888,
js::ProfileEntry::Category::NETWORK);
ASSERT_TRUE(profiler_get_backtrace());
#endif
profiler_stop();

View File

@ -930,19 +930,19 @@ CycleCollectedJSRuntime::GCNurseryCollectionCallback(JSContext* aContext,
timelines->AddMarkerForAllObservedDocShells(abstractMarker);
}
#ifdef MOZ_GECKO_PROFILER
if (aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START) {
self->mLatestNurseryCollectionStart = TimeStamp::Now();
} else if ((aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_END) &&
profiler_is_active())
{
#ifdef MOZ_GECKO_PROFILER
PROFILER_MARKER_PAYLOAD(
"GCMinor",
MakeUnique<GCMinorMarkerPayload>(self->mLatestNurseryCollectionStart,
TimeStamp::Now(),
JS::MinorGcToJSON(aContext)));
}
#endif
}
if (self->mPrevGCNurseryCollectionCallback) {
self->mPrevGCNurseryCollectionCallback(aContext, aProgress, aReason);

View File

@ -302,9 +302,7 @@ private:
JS::GCSliceCallback mPrevGCSliceCallback;
JS::GCNurseryCollectionCallback mPrevGCNurseryCollectionCallback;
#ifdef MOZ_GECKO_PROFILER
mozilla::TimeStamp mLatestNurseryCollectionStart;
#endif
nsDataHashtable<nsPtrHashKey<void>, nsScriptObjectTracer*> mJSHolders;

View File

@ -1010,7 +1010,6 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
NS_WARNING("Component Manager was never created ...");
}
#ifdef MOZ_GECKO_PROFILER
// In optimized builds we don't do shutdown collections by default, so
// uncollected (garbage) objects may keep the nsXPConnect singleton alive,
// and its XPCJSContext along with it. However, we still destroy various
@ -1020,7 +1019,6 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
// duplicating the call in XPCJSContext::~XPCJSContext() in case that
// never fired.
profiler_clear_js_context();
#endif
if (sInitializedJS) {
// Shut down the JS engine.