зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1360471 (part 4) - Use a bitfield to represent profiler features. r=mstange.
Currently the profiler mostly uses an array of strings to represent which features are available and in use. This patch changes the profiler core to use a uint32_t bitfield, which is a much simpler and faster representation. (nsProfiler and the profiler add-on still use the array of strings, alas.) The new ProfilerFeature type defines the values in the bitfield. One side-effect of this change is that profiler_feature_active() now can be used to query all features. Previously it was just a subset. Another side-effect is that profiler_get_available_features() no longer incorrectly indicates support for Java and stack-walking when they aren't supported. (The handling of task tracer support is unchanged, because the old code handled it correctly.)
This commit is contained in:
Родитель
cc78872f8c
Коммит
ea25e62e3c
|
@ -2570,18 +2570,12 @@ ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
|
|||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvStartProfiler(const ProfilerInitParams& params)
|
||||
{
|
||||
nsTArray<const char*> featureArray;
|
||||
for (size_t i = 0; i < params.features().Length(); ++i) {
|
||||
featureArray.AppendElement(params.features()[i].get());
|
||||
}
|
||||
|
||||
nsTArray<const char*> filterArray;
|
||||
for (size_t i = 0; i < params.filters().Length(); ++i) {
|
||||
filterArray.AppendElement(params.filters()[i].get());
|
||||
}
|
||||
|
||||
profiler_start(params.entries(), params.interval(),
|
||||
featureArray.Elements(), featureArray.Length(),
|
||||
profiler_start(params.entries(), params.interval(), params.features(),
|
||||
filterArray.Elements(), filterArray.Length());
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -2659,18 +2659,12 @@ PluginModuleChild::ProcessNativeEvents() {
|
|||
mozilla::ipc::IPCResult
|
||||
PluginModuleChild::RecvStartProfiler(const ProfilerInitParams& params)
|
||||
{
|
||||
nsTArray<const char*> featureArray;
|
||||
for (size_t i = 0; i < params.features().Length(); ++i) {
|
||||
featureArray.AppendElement(params.features()[i].get());
|
||||
}
|
||||
|
||||
nsTArray<const char*> filterArray;
|
||||
for (size_t i = 0; i < params.filters().Length(); ++i) {
|
||||
filterArray.AppendElement(params.filters()[i].get());
|
||||
}
|
||||
|
||||
profiler_start(params.entries(), params.interval(),
|
||||
featureArray.Elements(), featureArray.Length(),
|
||||
profiler_start(params.entries(), params.interval(), params.features(),
|
||||
filterArray.Elements(), filterArray.Length());
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -389,17 +389,11 @@ GPUParent::RecvNotifyGpuObservers(const nsCString& aTopic)
|
|||
mozilla::ipc::IPCResult
|
||||
GPUParent::RecvStartProfiler(const ProfilerInitParams& params)
|
||||
{
|
||||
nsTArray<const char*> featureArray;
|
||||
for (size_t i = 0; i < params.features().Length(); ++i) {
|
||||
featureArray.AppendElement(params.features()[i].get());
|
||||
}
|
||||
|
||||
nsTArray<const char*> filterArray;
|
||||
for (size_t i = 0; i < params.filters().Length(); ++i) {
|
||||
filterArray.AppendElement(params.filters()[i].get());
|
||||
}
|
||||
profiler_start(params.entries(), params.interval(),
|
||||
featureArray.Elements(), featureArray.Length(),
|
||||
profiler_start(params.entries(), params.interval(), params.features(),
|
||||
filterArray.Elements(), filterArray.Length());
|
||||
|
||||
return IPC_OK();
|
||||
|
|
|
@ -102,7 +102,7 @@ ContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
aStream << aPrefix;
|
||||
aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
|
||||
|
||||
if (profiler_feature_active("displaylistdump")) {
|
||||
if (profiler_feature_active(ProfilerFeature::DisplayListDump)) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
|
|
|
@ -1359,7 +1359,8 @@ TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
AppendToString(aStream, mFlags, " [flags=", "]");
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
|
||||
if (gfxPrefs::LayersDumpTexture() ||
|
||||
profiler_feature_active(ProfilerFeature::LayersDump)) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
|
|
|
@ -1397,7 +1397,7 @@ TiledContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
aStream << aPrefix;
|
||||
aStream << nsPrintfCString("%sTiledContentClient (0x%p)", mName, this).get();
|
||||
|
||||
if (profiler_feature_active("displaylistdump")) {
|
||||
if (profiler_feature_active(ProfilerFeature::DisplayListDump)) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
|
|
|
@ -836,7 +836,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
|
|||
// Dump to console
|
||||
if (gfxPrefs::LayersDump()) {
|
||||
this->Dump(/* aSorted= */true);
|
||||
} else if (profiler_feature_active("layersdump")) {
|
||||
} else if (profiler_feature_active(ProfilerFeature::LayersDump)) {
|
||||
std::stringstream ss;
|
||||
Dump(ss);
|
||||
profiler_log(ss.str().c_str());
|
||||
|
|
|
@ -408,7 +408,8 @@ TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
}
|
||||
AppendToString(aStream, mFlags, " [flags=", "]");
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
|
||||
if (gfxPrefs::LayersDumpTexture() ||
|
||||
profiler_feature_active(ProfilerFeature::LayersDump)) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
|
|
|
@ -625,7 +625,8 @@ TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|||
aStream << aPrefix;
|
||||
aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get();
|
||||
|
||||
if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
|
||||
if (gfxPrefs::LayersDumpTexture() ||
|
||||
profiler_feature_active(ProfilerFeature::LayersDump)) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace mozilla {
|
|||
void
|
||||
ContextStateTrackerOGL::PushOGLSection(GLContext* aGL, const char* aSectionName)
|
||||
{
|
||||
if (!profiler_feature_active("gpu")) {
|
||||
if (!profiler_feature_active(ProfilerFeature::GPU)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ RestyleTracker::DoProcessRestyles()
|
|||
}
|
||||
|
||||
Maybe<GeckoProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
if (profiler_feature_active(ProfilerFeature::Restyle)) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(data->mBacktrace));
|
||||
}
|
||||
ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint,
|
||||
|
@ -360,7 +360,7 @@ RestyleTracker::DoProcessRestyles()
|
|||
LOG_RESTYLE_INDENT();
|
||||
|
||||
Maybe<GeckoProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
if (profiler_feature_active(ProfilerFeature::Restyle)) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(currentRestyle->mBacktrace));
|
||||
}
|
||||
if (isTimelineRecording) {
|
||||
|
|
|
@ -259,7 +259,7 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
|||
if (!existingData) {
|
||||
RestyleData* rd =
|
||||
new RestyleData(aRestyleHint, aMinChangeHint, aRestyleHintData);
|
||||
if (profiler_feature_active("restyle")) {
|
||||
if (profiler_feature_active(ProfilerFeature::Restyle)) {
|
||||
rd->mBacktrace = profiler_get_backtrace();
|
||||
}
|
||||
mPendingRestyles.Put(aElement, rd);
|
||||
|
|
|
@ -3636,7 +3636,8 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
|
||||
startBuildDisplayList);
|
||||
|
||||
bool profilerNeedsDisplayList = profiler_feature_active("displaylistdump");
|
||||
bool profilerNeedsDisplayList =
|
||||
profiler_feature_active(ProfilerFeature::DisplayListDump);
|
||||
bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint();
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
FILE* savedDumpFile = gfxUtils::sDumpPaintFile;
|
||||
|
|
|
@ -253,67 +253,47 @@ NewSamplerThread(PSLockRef aLock, uint32_t aGeneration, double aInterval);
|
|||
class ActivePS
|
||||
{
|
||||
private:
|
||||
bool HasFeature(const char** aFeatures, uint32_t aFeatureCount,
|
||||
const char* aFeature)
|
||||
static uint32_t AdjustFeatures(uint32_t aFeatures, uint32_t aFilterCount)
|
||||
{
|
||||
for (size_t i = 0; i < aFeatureCount; i++) {
|
||||
if (strcmp(aFeatures[i], aFeature) == 0) {
|
||||
return true;
|
||||
}
|
||||
// Filter out any features unavailable in this platform/configuration.
|
||||
aFeatures &= profiler_get_available_features();
|
||||
|
||||
#if defined(PROFILE_JAVA)
|
||||
if (!mozilla::jni::IsFennec()) {
|
||||
aFeatures &= ~ProfilerFeature::Java;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Always enable ProfilerFeature::Threads if we have a filter, because
|
||||
// users sometimes ask to filter by a list of threads but forget to
|
||||
// explicitly specify ProfilerFeature::Threads.
|
||||
if (aFilterCount > 0) {
|
||||
aFeatures |= ProfilerFeature::Threads;
|
||||
}
|
||||
|
||||
return aFeatures;
|
||||
}
|
||||
|
||||
ActivePS(PSLockRef aLock, int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
const char** aFilters, uint32_t aFilterCount)
|
||||
uint32_t aFeatures, const char** aFilters, uint32_t aFilterCount)
|
||||
: mGeneration(sNextGeneration++)
|
||||
, mEntries(aEntries)
|
||||
, mInterval(aInterval)
|
||||
#define HAS_FEATURE(feature) HasFeature(aFeatures, aFeatureCount, feature)
|
||||
, mFeatureDisplayListDump(HAS_FEATURE("displaylistdump"))
|
||||
, mFeatureGPU(HAS_FEATURE("gpu"))
|
||||
#if defined(PROFILE_JAVA)
|
||||
, mFeatureJava(mozilla::jni::IsFennec() && HAS_FEATURE("java"))
|
||||
#else
|
||||
, mFeatureJava(false)
|
||||
#endif
|
||||
, mFeatureJS(HAS_FEATURE("js"))
|
||||
, mFeatureLayersDump(HAS_FEATURE("layersdump"))
|
||||
, mFeatureLeaf(HAS_FEATURE("leaf"))
|
||||
, mFeatureMainThreadIO(HAS_FEATURE("mainthreadio"))
|
||||
, mFeatureMemory(HAS_FEATURE("memory"))
|
||||
, mFeaturePrivacy(HAS_FEATURE("privacy"))
|
||||
, mFeatureRestyle(HAS_FEATURE("restyle"))
|
||||
, mFeatureStackWalk(HAS_FEATURE("stackwalk"))
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
, mFeatureTaskTracer(HAS_FEATURE("tasktracer"))
|
||||
#else
|
||||
, mFeatureTaskTracer(false)
|
||||
#endif
|
||||
// Profile non-main threads if we have a filter, because users sometimes
|
||||
// ask to filter by a list of threads but forget to explicitly request.
|
||||
, mFeatureThreads(HAS_FEATURE("threads") || aFilterCount > 0)
|
||||
#undef HAS_FEATURE
|
||||
, mFeatures(AdjustFeatures(aFeatures, aFilterCount))
|
||||
, mBuffer(new ProfileBuffer(aEntries))
|
||||
// The new sampler thread doesn't start sampling immediately because the
|
||||
// main loop within Run() is blocked until this function's caller unlocks
|
||||
// gPSMutex.
|
||||
, mSamplerThread(NewSamplerThread(aLock, mGeneration, aInterval))
|
||||
, mInterposeObserver(mFeatureMainThreadIO
|
||||
, mInterposeObserver(ProfilerFeature::HasMainThreadIO(aFeatures)
|
||||
? new mozilla::ProfilerIOInterposeObserver()
|
||||
: nullptr)
|
||||
#undef HAS_FEATURE
|
||||
, mIsPaused(false)
|
||||
#if defined(GP_OS_linux)
|
||||
, mWasPaused(false)
|
||||
#endif
|
||||
{
|
||||
// Deep copy aFeatures.
|
||||
MOZ_ALWAYS_TRUE(mFeatures.resize(aFeatureCount));
|
||||
for (uint32_t i = 0; i < aFeatureCount; ++i) {
|
||||
mFeatures[i] = aFeatures[i];
|
||||
}
|
||||
|
||||
// Deep copy aFilters.
|
||||
MOZ_ALWAYS_TRUE(mFilters.resize(aFilterCount));
|
||||
for (uint32_t i = 0; i < aFilterCount; ++i) {
|
||||
|
@ -362,11 +342,11 @@ private:
|
|||
|
||||
public:
|
||||
static void Create(PSLockRef aLock, int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount)
|
||||
{
|
||||
sInstance = new ActivePS(aLock, aEntries, aInterval, aFeatures,
|
||||
aFeatureCount, aFilters, aFilterCount);
|
||||
aFilters, aFilterCount);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE SamplerThread* Destroy(PSLockRef aLock)
|
||||
|
@ -395,7 +375,7 @@ public:
|
|||
|
||||
MOZ_RELEASE_ASSERT(sInstance);
|
||||
|
||||
return ((aInfo->IsMainThread() || sInstance->mFeatureThreads) &&
|
||||
return ((aInfo->IsMainThread() || FeatureThreads(aLock)) &&
|
||||
sInstance->ThreadSelected(aInfo->Name()));
|
||||
}
|
||||
|
||||
|
@ -405,24 +385,20 @@ public:
|
|||
|
||||
PS_GET(double, Interval)
|
||||
|
||||
PS_GET(const Vector<std::string>&, Features)
|
||||
PS_GET(uint32_t, Features)
|
||||
|
||||
#define PS_GET_FEATURE(n_, str_, Name_) \
|
||||
static bool Feature##Name_(PSLockRef) \
|
||||
{ \
|
||||
return ProfilerFeature::Has##Name_(sInstance->mFeatures); \
|
||||
}
|
||||
|
||||
PROFILER_FOR_EACH_FEATURE(PS_GET_FEATURE)
|
||||
|
||||
#undef PS_GET_FEATURE
|
||||
|
||||
PS_GET(const Vector<std::string>&, Filters)
|
||||
|
||||
PS_GET(bool, FeatureDisplayListDump)
|
||||
PS_GET(bool, FeatureGPU)
|
||||
PS_GET(bool, FeatureJava)
|
||||
PS_GET(bool, FeatureJS)
|
||||
PS_GET(bool, FeatureLayersDump)
|
||||
PS_GET(bool, FeatureLeaf)
|
||||
PS_GET(bool, FeatureMainThreadIO)
|
||||
PS_GET(bool, FeatureMemory)
|
||||
PS_GET(bool, FeaturePrivacy)
|
||||
PS_GET(bool, FeatureRestyle)
|
||||
PS_GET(bool, FeatureStackWalk)
|
||||
PS_GET(bool, FeatureTaskTracer)
|
||||
PS_GET(bool, FeatureThreads)
|
||||
|
||||
static ProfileBuffer* Buffer(PSLockRef) { return sInstance->mBuffer.get(); }
|
||||
|
||||
PS_GET_AND_SET(bool, IsPaused)
|
||||
|
@ -462,26 +438,11 @@ private:
|
|||
const double mInterval;
|
||||
|
||||
// The profile features that are enabled.
|
||||
Vector<std::string> mFeatures;
|
||||
const uint32_t mFeatures;
|
||||
|
||||
// Substrings of names of threads we want to profile.
|
||||
Vector<std::string> mFilters;
|
||||
|
||||
// Configuration flags derived from mFeatures.
|
||||
const bool mFeatureDisplayListDump;
|
||||
const bool mFeatureGPU;
|
||||
const bool mFeatureJava;
|
||||
const bool mFeatureJS;
|
||||
const bool mFeatureLayersDump;
|
||||
const bool mFeatureLeaf;
|
||||
const bool mFeatureMainThreadIO;
|
||||
const bool mFeatureMemory;
|
||||
const bool mFeaturePrivacy;
|
||||
const bool mFeatureRestyle;
|
||||
const bool mFeatureStackWalk;
|
||||
const bool mFeatureTaskTracer;
|
||||
const bool mFeatureThreads;
|
||||
|
||||
// The buffer into which all samples are recorded. Always used in conjunction
|
||||
// with CorePS::m{Live,Dead}Threads.
|
||||
const UniquePtr<ProfileBuffer> mBuffer;
|
||||
|
@ -1998,8 +1959,7 @@ locked_register_thread(PSLockRef aLock, const char* aName, void* stackTop)
|
|||
}
|
||||
|
||||
static void
|
||||
NotifyProfilerStarted(const int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
NotifyProfilerStarted(const int aEntries, double aInterval, uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount)
|
||||
{
|
||||
if (!CanNotifyObservers()) {
|
||||
|
@ -2011,18 +1971,13 @@ NotifyProfilerStarted(const int aEntries, double aInterval,
|
|||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> featuresArray;
|
||||
for (size_t i = 0; i < aFeatureCount; ++i) {
|
||||
featuresArray.AppendElement(aFeatures[i]);
|
||||
}
|
||||
|
||||
nsTArray<nsCString> filtersArray;
|
||||
for (size_t i = 0; i < aFilterCount; ++i) {
|
||||
filtersArray.AppendElement(aFilters[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIProfilerStartParams> params =
|
||||
new nsProfilerStartParams(aEntries, aInterval, featuresArray, filtersArray);
|
||||
new nsProfilerStartParams(aEntries, aInterval, aFeatures, filtersArray);
|
||||
|
||||
os->NotifyObservers(params, "profiler-started", nullptr);
|
||||
}
|
||||
|
@ -2044,7 +1999,7 @@ NotifyObservers(const char* aTopic)
|
|||
|
||||
static void
|
||||
locked_profiler_start(PSLockRef aLock, const int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount);
|
||||
|
||||
void
|
||||
|
@ -2054,16 +2009,17 @@ profiler_init(void* aStackTop)
|
|||
|
||||
MOZ_RELEASE_ASSERT(!CorePS::Exists());
|
||||
|
||||
const char* features[] = { "js"
|
||||
uint32_t features =
|
||||
#if defined(PROFILE_JAVA)
|
||||
, "java"
|
||||
ProfilerFeature::Java |
|
||||
#endif
|
||||
, "leaf"
|
||||
ProfilerFeature::JS |
|
||||
ProfilerFeature::Leaf |
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
, "stackwalk"
|
||||
ProfilerFeature::StackWalk |
|
||||
#endif
|
||||
, "threads"
|
||||
};
|
||||
ProfilerFeature::Threads |
|
||||
0;
|
||||
|
||||
const char* filters[] = { "GeckoMain", "Compositor" };
|
||||
|
||||
|
@ -2129,16 +2085,14 @@ profiler_init(void* aStackTop)
|
|||
}
|
||||
}
|
||||
|
||||
locked_profiler_start(lock, entries, interval,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
locked_profiler_start(lock, entries, interval, features,
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
}
|
||||
|
||||
// We do this with gPSMutex unlocked. The comment in profiler_stop() explains
|
||||
// why.
|
||||
NotifyProfilerStarted(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2216,8 +2170,7 @@ profiler_get_profile(double aSinceTime)
|
|||
}
|
||||
|
||||
void
|
||||
profiler_get_start_params(int* aEntries, double* aInterval,
|
||||
mozilla::Vector<const char*>* aFeatures,
|
||||
profiler_get_start_params(int* aEntries, double* aInterval, uint32_t* aFeatures,
|
||||
mozilla::Vector<const char*>* aFilters)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
@ -2233,19 +2186,14 @@ profiler_get_start_params(int* aEntries, double* aInterval,
|
|||
if (!ActivePS::Exists(lock)) {
|
||||
*aEntries = 0;
|
||||
*aInterval = 0;
|
||||
aFeatures->clear();
|
||||
*aFeatures = 0;
|
||||
aFilters->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
*aEntries = ActivePS::Entries(lock);
|
||||
*aInterval = ActivePS::Interval(lock);
|
||||
|
||||
const Vector<std::string>& features = ActivePS::Features(lock);
|
||||
MOZ_ALWAYS_TRUE(aFeatures->resize(features.length()));
|
||||
for (size_t i = 0; i < features.length(); ++i) {
|
||||
(*aFeatures)[i] = features[i].c_str();
|
||||
}
|
||||
*aFeatures = ActivePS::Features(lock);
|
||||
|
||||
const Vector<std::string>& filters = ActivePS::Filters(lock);
|
||||
MOZ_ALWAYS_TRUE(aFilters->resize(filters.length()));
|
||||
|
@ -2298,46 +2246,31 @@ profiler_save_profile_to_file(const char* aFilename)
|
|||
locked_profiler_save_profile_to_file(lock, aFilename);
|
||||
}
|
||||
|
||||
const char**
|
||||
uint32_t
|
||||
profiler_get_available_features()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
MOZ_RELEASE_ASSERT(CorePS::Exists());
|
||||
|
||||
static const char* features[] = {
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
// Walk the C++ stack.
|
||||
"stackwalk",
|
||||
uint32_t features = 0;
|
||||
|
||||
#define ADD_FEATURE(n_, str_, Name_) ProfilerFeature::Set##Name_(features);
|
||||
|
||||
// Add all the possible features.
|
||||
PROFILER_FOR_EACH_FEATURE(ADD_FEATURE)
|
||||
|
||||
#undef ADD_FEATURE
|
||||
|
||||
// Now remove features not supported on this platform/configuration.
|
||||
#if !defined(PROFILE_JAVA)
|
||||
ProfilerFeature::ClearJava(features);
|
||||
#endif
|
||||
// Include the C++ leaf node if not stackwalking. DevTools
|
||||
// profiler doesn't want the native addresses.
|
||||
"leaf",
|
||||
// Profile Java code (Android only).
|
||||
"java",
|
||||
// Tell the JS engine to emit pseudostack entries in the prologue/epilogue.
|
||||
"js",
|
||||
// GPU Profiling (may not be supported by the GL)
|
||||
"gpu",
|
||||
// Profile the registered secondary threads.
|
||||
"threads",
|
||||
// Do not include user-identifiable information
|
||||
"privacy",
|
||||
// Dump the layer tree with the textures.
|
||||
"layersdump",
|
||||
// Dump the display list with the textures.
|
||||
"displaylistdump",
|
||||
// Add main thread I/O to the profile
|
||||
"mainthreadio",
|
||||
// Add RSS collection
|
||||
"memory",
|
||||
// Restyle profiling.
|
||||
"restyle",
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
// Start profiling with feature TaskTracer.
|
||||
"tasktracer",
|
||||
#if !defined(HAVE_NATIVE_UNWIND)
|
||||
ProfilerFeature::ClearStackWalk(features);
|
||||
#endif
|
||||
#if !defined(MOZ_TASK_TRACER)
|
||||
ProfilerFeature::ClearTaskTracer(features);
|
||||
#endif
|
||||
nullptr
|
||||
};
|
||||
|
||||
return features;
|
||||
}
|
||||
|
@ -2366,16 +2299,23 @@ profiler_get_buffer_info_helper(uint32_t* aCurrentPosition,
|
|||
|
||||
static void
|
||||
locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount)
|
||||
{
|
||||
if (LOG_TEST) {
|
||||
LOG("locked_profiler_start");
|
||||
LOG("- entries = %d", aEntries);
|
||||
LOG("- interval = %.2f", aInterval);
|
||||
for (uint32_t i = 0; i < aFeatureCount; i++) {
|
||||
LOG("- feature = %s", aFeatures[i]);
|
||||
}
|
||||
|
||||
#define LOG_FEATURE(n_, str_, Name_) \
|
||||
if (ProfilerFeature::Has##Name_(aFeatures)) { \
|
||||
LOG("- feature = %s", str_); \
|
||||
}
|
||||
|
||||
PROFILER_FOR_EACH_FEATURE(LOG_FEATURE)
|
||||
|
||||
#undef LOG_FEATURE
|
||||
|
||||
for (uint32_t i = 0; i < aFilterCount; i++) {
|
||||
LOG("- threads = %s", aFilters[i]);
|
||||
}
|
||||
|
@ -2388,8 +2328,7 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
|
|||
int entries = aEntries > 0 ? aEntries : PROFILER_DEFAULT_ENTRIES;
|
||||
double interval = aInterval > 0 ? aInterval : PROFILER_DEFAULT_INTERVAL;
|
||||
|
||||
ActivePS::Create(aLock, entries, interval, aFeatures, aFeatureCount,
|
||||
aFilters, aFilterCount);
|
||||
ActivePS::Create(aLock, entries, interval, aFeatures, aFilters, aFilterCount);
|
||||
|
||||
// Set up profiling for each registered thread, if appropriate.
|
||||
Thread::tid_t tid = Thread::GetCurrentId();
|
||||
|
@ -2434,8 +2373,7 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
|
|||
}
|
||||
|
||||
void
|
||||
profiler_start(int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
profiler_start(int aEntries, double aInterval, uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount)
|
||||
{
|
||||
LOG("profiler_start");
|
||||
|
@ -2456,7 +2394,7 @@ profiler_start(int aEntries, double aInterval,
|
|||
samplerThread = locked_profiler_stop(lock);
|
||||
}
|
||||
|
||||
locked_profiler_start(lock, aEntries, aInterval, aFeatures, aFeatureCount,
|
||||
locked_profiler_start(lock, aEntries, aInterval, aFeatures,
|
||||
aFilters, aFilterCount);
|
||||
}
|
||||
|
||||
|
@ -2466,7 +2404,7 @@ profiler_start(int aEntries, double aInterval,
|
|||
NotifyObservers("profiler-stopped");
|
||||
delete samplerThread;
|
||||
}
|
||||
NotifyProfilerStarted(aEntries, aInterval, aFeatures, aFeatureCount,
|
||||
NotifyProfilerStarted(aEntries, aInterval, aFeatures,
|
||||
aFilters, aFilterCount);
|
||||
}
|
||||
|
||||
|
@ -2614,7 +2552,7 @@ profiler_resume()
|
|||
}
|
||||
|
||||
bool
|
||||
profiler_feature_active(const char* aName)
|
||||
profiler_feature_active(uint32_t aFeature)
|
||||
{
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
|
@ -2626,23 +2564,7 @@ profiler_feature_active(const char* aName)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(aName, "displaylistdump") == 0) {
|
||||
return ActivePS::FeatureDisplayListDump(lock);
|
||||
}
|
||||
|
||||
if (strcmp(aName, "gpu") == 0) {
|
||||
return ActivePS::FeatureGPU(lock);
|
||||
}
|
||||
|
||||
if (strcmp(aName, "layersdump") == 0) {
|
||||
return ActivePS::FeatureLayersDump(lock);
|
||||
}
|
||||
|
||||
if (strcmp(aName, "restyle") == 0) {
|
||||
return ActivePS::FeatureRestyle(lock);
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!(ActivePS::Features(lock) & aFeature);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -104,7 +104,7 @@ CrossProcessProfilerController::StartProfiler(nsIProfilerStartParams* aParams)
|
|||
ipcParams.enabled() = true;
|
||||
aParams->GetEntries(&ipcParams.entries());
|
||||
aParams->GetInterval(&ipcParams.interval());
|
||||
ipcParams.features() = aParams->GetFeatures();
|
||||
aParams->GetFeatures(&ipcParams.features());
|
||||
ipcParams.filters() = aParams->GetFilters();
|
||||
|
||||
mProcess->SendStartProfiler(ipcParams);
|
||||
|
|
|
@ -9,8 +9,8 @@ struct ProfilerInitParams {
|
|||
bool enabled;
|
||||
uint32_t entries;
|
||||
double interval;
|
||||
uint32_t features;
|
||||
nsCString[] filters;
|
||||
nsCString[] features;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -22,8 +22,8 @@ interface nsIProfilerStartParams : nsISupports
|
|||
{
|
||||
readonly attribute uint32_t entries;
|
||||
readonly attribute double interval;
|
||||
readonly attribute uint32_t features;
|
||||
|
||||
[noscript, notxpcom, nostdcall] StringArrayRef getFeatures();
|
||||
[noscript, notxpcom, nostdcall] StringArrayRef getFilters();
|
||||
};
|
||||
|
||||
|
|
|
@ -93,6 +93,17 @@ nsProfiler::CanProfile(bool *aCanProfile)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
HasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature)
|
||||
{
|
||||
for (size_t i = 0; i < aFeatureCount; i++) {
|
||||
if (strcmp(aFeatures[i], aFeature) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
|
@ -102,8 +113,18 @@ nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
profiler_start(aEntries, aInterval,
|
||||
aFeatures, aFeatureCount, aFilters, aFilterCount);
|
||||
#define ADD_FEATURE_BIT(n_, str_, Name_) \
|
||||
if (HasFeature(aFeatures, aFeatureCount, str_)) { \
|
||||
features |= ProfilerFeature::Name_; \
|
||||
}
|
||||
|
||||
// Convert the array of strings to a bitfield.
|
||||
uint32_t features = 0;
|
||||
PROFILER_FOR_EACH_FEATURE(ADD_FEATURE_BIT)
|
||||
|
||||
#undef ADD_FEATURE_BIT
|
||||
|
||||
profiler_start(aEntries, aInterval, features, aFilters, aFilterCount);
|
||||
|
||||
// Do this after profiler_start().
|
||||
mGatherer = new ProfileGatherer();
|
||||
|
@ -340,31 +361,38 @@ nsProfiler::IsActive(bool *aIsActive)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProfiler::GetFeatures(uint32_t *aCount, char ***aFeatures)
|
||||
nsProfiler::GetFeatures(uint32_t* aCount, char*** aFeatureList)
|
||||
{
|
||||
uint32_t features = profiler_get_available_features();
|
||||
|
||||
#define COUNT_IF_SET(n_, str_, Name_) \
|
||||
if (ProfilerFeature::Has##Name_(features)) { \
|
||||
len++; \
|
||||
}
|
||||
|
||||
// Count the number of features in use.
|
||||
uint32_t len = 0;
|
||||
PROFILER_FOR_EACH_FEATURE(COUNT_IF_SET)
|
||||
|
||||
const char** features = profiler_get_available_features();
|
||||
if (!features) {
|
||||
*aCount = 0;
|
||||
*aFeatures = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
#undef COUNT_IF_SET
|
||||
|
||||
while (features[len]) {
|
||||
len++;
|
||||
}
|
||||
auto featureList = static_cast<char**>(moz_xmalloc(len * sizeof(char*)));
|
||||
|
||||
char **featureList = static_cast<char **>
|
||||
(moz_xmalloc(len * sizeof(char*)));
|
||||
#define DUP_IF_SET(n_, str_, Name_) \
|
||||
if (ProfilerFeature::Has##Name_(features)) { \
|
||||
size_t strLen = strlen(str_); \
|
||||
featureList[i] = static_cast<char*>( \
|
||||
nsMemory::Clone(str_, (strLen + 1) * sizeof(char))); \
|
||||
i++; \
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
size_t strLen = strlen(features[i]);
|
||||
featureList[i] = static_cast<char *>
|
||||
(nsMemory::Clone(features[i], (strLen + 1) * sizeof(char)));
|
||||
}
|
||||
// Insert the strings for the features in use.
|
||||
size_t i = 0;
|
||||
PROFILER_FOR_EACH_FEATURE(DUP_IF_SET)
|
||||
|
||||
*aFeatures = featureList;
|
||||
#undef STRDUP_IF_SET
|
||||
|
||||
*aFeatureList = featureList;
|
||||
*aCount = len;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -377,22 +405,17 @@ nsProfiler::GetStartParams(nsIProfilerStartParams** aRetVal)
|
|||
} else {
|
||||
int entries = 0;
|
||||
double interval = 0;
|
||||
uint32_t features = 0;
|
||||
mozilla::Vector<const char*> filters;
|
||||
mozilla::Vector<const char*> features;
|
||||
profiler_get_start_params(&entries, &interval, &features, &filters);
|
||||
|
||||
nsTArray<nsCString> featuresArray;
|
||||
for (size_t i = 0; i < features.length(); ++i) {
|
||||
featuresArray.AppendElement(features[i]);
|
||||
}
|
||||
|
||||
nsTArray<nsCString> filtersArray;
|
||||
for (uint32_t i = 0; i < filters.length(); ++i) {
|
||||
filtersArray.AppendElement(filters[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIProfilerStartParams> startParams =
|
||||
new nsProfilerStartParams(entries, interval, featuresArray, filtersArray);
|
||||
new nsProfilerStartParams(entries, interval, features, filtersArray);
|
||||
|
||||
startParams.forget(aRetVal);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ NS_IMPL_ISUPPORTS(nsProfilerStartParams, nsIProfilerStartParams)
|
|||
|
||||
nsProfilerStartParams::nsProfilerStartParams(uint32_t aEntries,
|
||||
double aInterval,
|
||||
const nsTArray<nsCString>& aFeatures,
|
||||
uint32_t aFeatures,
|
||||
const nsTArray<nsCString>& aFilters) :
|
||||
mEntries(aEntries),
|
||||
mInterval(aInterval),
|
||||
|
@ -38,10 +38,12 @@ nsProfilerStartParams::GetInterval(double* aInterval)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsTArray<nsCString>&
|
||||
nsProfilerStartParams::GetFeatures()
|
||||
NS_IMETHODIMP
|
||||
nsProfilerStartParams::GetFeatures(uint32_t* aFeatures)
|
||||
{
|
||||
return mFeatures;
|
||||
NS_ENSURE_ARG_POINTER(aFeatures);
|
||||
*aFeatures = mFeatures;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsTArray<nsCString>&
|
||||
|
|
|
@ -18,14 +18,14 @@ public:
|
|||
|
||||
nsProfilerStartParams(uint32_t aEntries,
|
||||
double aInterval,
|
||||
const nsTArray<nsCString>& aFeatures,
|
||||
uint32_t aFeatures,
|
||||
const nsTArray<nsCString>& aFilters);
|
||||
|
||||
private:
|
||||
virtual ~nsProfilerStartParams();
|
||||
uint32_t mEntries;
|
||||
double mInterval;
|
||||
nsTArray<nsCString> mFeatures;
|
||||
uint32_t mFeatures;
|
||||
nsTArray<nsCString> mFilters;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 2; 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/. */
|
||||
|
@ -109,6 +110,64 @@ using UniqueProfilerBacktrace =
|
|||
|
||||
#else // 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.
|
||||
#define PROFILER_FOR_EACH_FEATURE(macro) \
|
||||
/* Dump the display list with the textures. */ \
|
||||
macro(0, "displaylistdump", DisplayListDump) \
|
||||
\
|
||||
/* GPU Profiling (may not be supported by the GL). */ \
|
||||
macro(1, "gpu", GPU) \
|
||||
\
|
||||
/* Profile Java code (Android only). */ \
|
||||
macro(2, "java", Java) \
|
||||
\
|
||||
/* Get the JS engine to emit pseudostack entries in prologues/epilogues */ \
|
||||
macro(3, "js", JS) \
|
||||
\
|
||||
/* Dump the layer tree with the textures. */ \
|
||||
macro(4, "layersdump", LayersDump) \
|
||||
\
|
||||
/* Include the C++ leaf node if not stackwalking. */ \
|
||||
/* The DevTools profiler doesn't want the native addresses. */ \
|
||||
macro(5, "leaf", Leaf) \
|
||||
\
|
||||
/* Add main thread I/O to the profile. */ \
|
||||
macro(6, "mainthreadio", MainThreadIO) \
|
||||
\
|
||||
/* Add memory measurements (e.g. RSS). */ \
|
||||
macro(7, "memory", Memory) \
|
||||
\
|
||||
/* Do not include user-identifiable information. */ \
|
||||
macro(8, "privacy", Privacy) \
|
||||
\
|
||||
/* Restyle profiling. */ \
|
||||
macro(9, "restyle", Restyle) \
|
||||
\
|
||||
/* Walk the C++ stack. Not available on all platforms. */ \
|
||||
macro(10, "stackwalk", StackWalk) \
|
||||
\
|
||||
/* Start profiling with feature TaskTracer. */ \
|
||||
macro(11, "tasktracer", TaskTracer) \
|
||||
\
|
||||
/* Profile the registered secondary threads. */ \
|
||||
macro(12, "threads", Threads)
|
||||
|
||||
struct ProfilerFeature
|
||||
{
|
||||
#define DECLARE(n_, str_, Name_) \
|
||||
static const uint32_t Name_ = (1u << n_); \
|
||||
static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
|
||||
static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
|
||||
static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }
|
||||
|
||||
// Define a bitfield constant, a getter, and two setters for each feature.
|
||||
PROFILER_FOR_EACH_FEATURE(DECLARE)
|
||||
|
||||
#undef DECLARE
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
# define PROFILER_FUNCTION_NAME __FUNCTION__
|
||||
#else
|
||||
|
@ -172,11 +231,11 @@ PROFILER_FUNC_VOID(profiler_shutdown())
|
|||
// circular buffer.
|
||||
// "aEntries" is the number of entries in the profiler's circular buffer.
|
||||
// "aInterval" the sampling interval, measured in millseconds.
|
||||
// "aFeatures" is the feature set. Features unsupported by this
|
||||
// platform/configuration are ignored.
|
||||
PROFILER_FUNC_VOID(profiler_start(int aEntries, double aInterval,
|
||||
const char** aFeatures,
|
||||
uint32_t aFeatureCount,
|
||||
const char** aFilters,
|
||||
uint32_t aFilterCount))
|
||||
uint32_t aFeatures,
|
||||
const char** aFilters, uint32_t aFilterCount))
|
||||
|
||||
// Stop the profiler and discard the profile without saving it. A no-op if the
|
||||
// profiler is inactive. After stopping the profiler is "inactive".
|
||||
|
@ -226,11 +285,9 @@ ProfilerBacktraceDestructor::operator()(ProfilerBacktrace* aBacktrace) {}
|
|||
//
|
||||
PROFILER_FUNC(bool profiler_is_active(), false)
|
||||
|
||||
// Check if a profiler feature is active. Returns false if the profiler is
|
||||
// inactive.
|
||||
//
|
||||
// Supported features: "displaylistdump", "gpu", "layersdump", "restyle".
|
||||
PROFILER_FUNC(bool profiler_feature_active(const char*), false)
|
||||
// Check if a profiler feature (specified via the ProfilerFeature type) is
|
||||
// active. Returns false if the profiler is inactive.
|
||||
PROFILER_FUNC(bool profiler_feature_active(uint32_t aFeature), false)
|
||||
|
||||
// Get the profile encoded as a JSON string. A no-op (returning nullptr) if the
|
||||
// profiler is inactive.
|
||||
|
@ -243,11 +300,13 @@ PROFILER_FUNC(bool profiler_stream_json_for_this_process(SpliceableJSONWriter& a
|
|||
double aSinceTime = 0),
|
||||
false)
|
||||
|
||||
// Get the params used to start the profiler. Returns 0 and empty vectors (via
|
||||
// outparams) if the profile is inactive.
|
||||
// Get the params used to start the profiler. Returns 0 and an empty vector
|
||||
// (via outparams) if the profile is inactive. It's possible that the features
|
||||
// returned may be slightly different to those requested due to requied
|
||||
// adjustments.
|
||||
PROFILER_FUNC_VOID(profiler_get_start_params(int* aEntrySize,
|
||||
double* aInterval,
|
||||
mozilla::Vector<const char*>* aFeatures,
|
||||
uint32_t* aFeatures,
|
||||
mozilla::Vector<const char*>* aFilters))
|
||||
|
||||
// Get the profile and write it into a file. A no-op if the profile is
|
||||
|
@ -261,9 +320,9 @@ PROFILER_FUNC_VOID(profiler_save_profile_to_file(const char* aFilename))
|
|||
}
|
||||
|
||||
// Get all the features supported by the profiler that are accepted by
|
||||
// profiler_start(). Returns a null terminated char* array. The result is the
|
||||
// same whether the profiler is active or not.
|
||||
PROFILER_FUNC(const char** profiler_get_available_features(), nullptr)
|
||||
// profiler_start(). The result is the same whether the profiler is active or
|
||||
// not.
|
||||
PROFILER_FUNC(uint32_t profiler_get_available_features(), 0)
|
||||
|
||||
// Get information about the current buffer status. A no-op when the profiler
|
||||
// is inactive. Do not call this function; call profiler_get_buffer_info()
|
||||
|
|
|
@ -33,40 +33,36 @@ InactiveFeaturesAndParamsCheck()
|
|||
{
|
||||
int entries;
|
||||
double interval;
|
||||
StrVec features;
|
||||
uint32_t features;
|
||||
StrVec filters;
|
||||
|
||||
ASSERT_TRUE(!profiler_is_active());
|
||||
ASSERT_TRUE(!profiler_feature_active("gpu"));
|
||||
ASSERT_TRUE(!profiler_feature_active("privacy"));
|
||||
ASSERT_TRUE(!profiler_feature_active("restyle"));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::GPU));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Privacy));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
|
||||
|
||||
profiler_get_start_params(&entries, &interval, &features, &filters);
|
||||
|
||||
ASSERT_TRUE(entries == 0);
|
||||
ASSERT_TRUE(interval == 0);
|
||||
ASSERT_TRUE(features.empty());
|
||||
ASSERT_TRUE(features == 0);
|
||||
ASSERT_TRUE(filters.empty());
|
||||
}
|
||||
|
||||
void
|
||||
ActiveParamsCheck(int aEntries, double aInterval,
|
||||
const char** aFeatures, size_t aFeaturesLen,
|
||||
ActiveParamsCheck(int aEntries, double aInterval, uint32_t aFeatures,
|
||||
const char** aFilters, size_t aFiltersLen)
|
||||
{
|
||||
int entries;
|
||||
double interval;
|
||||
StrVec features;
|
||||
uint32_t features;
|
||||
StrVec filters;
|
||||
|
||||
profiler_get_start_params(&entries, &interval, &features, &filters);
|
||||
|
||||
ASSERT_TRUE(entries == aEntries);
|
||||
ASSERT_TRUE(interval == aInterval);
|
||||
ASSERT_TRUE(features.length() == aFeaturesLen);
|
||||
for (size_t i = 0; i < aFeaturesLen; i++) {
|
||||
ASSERT_TRUE(strcmp(features[i], aFeatures[i]) == 0);
|
||||
}
|
||||
ASSERT_TRUE(features == aFeatures);
|
||||
ASSERT_TRUE(filters.length() == aFiltersLen);
|
||||
for (size_t i = 0; i < aFiltersLen; i++) {
|
||||
ASSERT_TRUE(strcmp(filters[i], aFilters[i]) == 0);
|
||||
|
@ -79,21 +75,19 @@ TEST(GeckoProfiler, FeaturesAndParams)
|
|||
|
||||
// Try a couple of features and filters.
|
||||
{
|
||||
const char* features[] = { "js", "threads" };
|
||||
uint32_t features = ProfilerFeature::JS | ProfilerFeature::Threads;
|
||||
const char* filters[] = { "GeckoMain", "Compositor" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(profiler_is_active());
|
||||
ASSERT_TRUE(!profiler_feature_active("gpu"));
|
||||
ASSERT_TRUE(!profiler_feature_active("privacy"));
|
||||
ASSERT_TRUE(!profiler_feature_active("restyle"));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::GPU));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Privacy));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
|
||||
|
||||
ActiveParamsCheck(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
profiler_stop();
|
||||
|
||||
|
@ -102,22 +96,20 @@ TEST(GeckoProfiler, FeaturesAndParams)
|
|||
|
||||
// Try some different features and filters.
|
||||
{
|
||||
const char* features[] = { "gpu", "privacy", "no-such-feature" };
|
||||
uint32_t features = ProfilerFeature::GPU | ProfilerFeature::Privacy;
|
||||
const char* filters[] = { "GeckoMain", "Foo", "Bar" };
|
||||
|
||||
profiler_start(999999, 3,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
// Nb: we did specify "privacy", but profiler_feature_active() doesn't
|
||||
// support querying "privacy".
|
||||
ASSERT_TRUE(profiler_is_active());
|
||||
ASSERT_TRUE(profiler_feature_active("gpu"));
|
||||
ASSERT_TRUE(!profiler_feature_active("privacy"));
|
||||
ASSERT_TRUE(!profiler_feature_active("restyle"));
|
||||
ASSERT_TRUE(profiler_feature_active(ProfilerFeature::GPU));
|
||||
ASSERT_TRUE(profiler_feature_active(ProfilerFeature::Privacy));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
|
||||
|
||||
// Profiler::Threads is added because filters has multiple entries.
|
||||
ActiveParamsCheck(999999, 3,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
features | ProfilerFeature::Threads,
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
profiler_stop();
|
||||
|
@ -127,50 +119,41 @@ TEST(GeckoProfiler, FeaturesAndParams)
|
|||
|
||||
// Try all supported features, and filters that match all threads.
|
||||
{
|
||||
const char** availableFeatures = profiler_get_available_features();
|
||||
int n = 0;
|
||||
while (availableFeatures[n]) {
|
||||
n++;
|
||||
}
|
||||
// There are 11 features supported on all platforms, and 2 features
|
||||
// supported on some platforms.
|
||||
ASSERT_TRUE(11 <= n && n <= 13);
|
||||
|
||||
uint32_t availableFeatures = profiler_get_available_features();
|
||||
const char* filters[] = { "" };
|
||||
|
||||
profiler_start(88888, 10,
|
||||
availableFeatures, n, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
availableFeatures, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(profiler_is_active());
|
||||
ASSERT_TRUE(profiler_feature_active("gpu"));
|
||||
ASSERT_TRUE(!profiler_feature_active("privacy"));
|
||||
ASSERT_TRUE(profiler_feature_active("restyle"));
|
||||
ASSERT_TRUE(profiler_feature_active(ProfilerFeature::GPU));
|
||||
ASSERT_TRUE(profiler_feature_active(ProfilerFeature::Privacy));
|
||||
ASSERT_TRUE(profiler_feature_active(ProfilerFeature::Restyle));
|
||||
|
||||
ActiveParamsCheck(88888, 10,
|
||||
availableFeatures, n, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
availableFeatures, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
// Don't call profiler_stop() here.
|
||||
}
|
||||
|
||||
// Try no features, and filters that match no threads.
|
||||
{
|
||||
const char* features[] = { "" };
|
||||
uint32_t features = 0;
|
||||
const char* filters[] = { "NoThreadWillMatchThis" };
|
||||
|
||||
// Second profiler_start() call in a row without an intervening
|
||||
// profiler_stop(); this will do an implicit profiler_stop() and restart.
|
||||
profiler_start(0, 0,
|
||||
features, 0,
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(profiler_is_active());
|
||||
ASSERT_TRUE(!profiler_feature_active("gpu"));
|
||||
ASSERT_TRUE(!profiler_feature_active("privacy"));
|
||||
ASSERT_TRUE(!profiler_feature_active("restyle"));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::GPU));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Privacy));
|
||||
ASSERT_TRUE(!profiler_feature_active(ProfilerFeature::Restyle));
|
||||
|
||||
// Entries and intervals go to defaults if 0 is specified.
|
||||
ActiveParamsCheck(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, 0,
|
||||
features | ProfilerFeature::Threads,
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
profiler_stop();
|
||||
|
@ -190,12 +173,11 @@ TEST(GeckoProfiler, GetBacktrace)
|
|||
ASSERT_TRUE(!profiler_get_backtrace());
|
||||
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
// These will be destroyed while the profiler is active.
|
||||
static const int N = 100;
|
||||
|
@ -218,14 +200,13 @@ TEST(GeckoProfiler, GetBacktrace)
|
|||
}
|
||||
|
||||
{
|
||||
const char* features[] = { "privacy" };
|
||||
uint32_t features = ProfilerFeature::Privacy;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
// No backtraces obtained when the "privacy" feature is set.
|
||||
// No backtraces obtained when ProfilerFeature::Privacy is set.
|
||||
ASSERT_TRUE(!profiler_get_backtrace());
|
||||
|
||||
profiler_stop();
|
||||
|
@ -236,14 +217,13 @@ TEST(GeckoProfiler, GetBacktrace)
|
|||
|
||||
TEST(GeckoProfiler, Pause)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
ASSERT_TRUE(!profiler_is_paused());
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(!profiler_is_paused());
|
||||
|
||||
|
@ -277,12 +257,11 @@ TEST(GeckoProfiler, Pause)
|
|||
|
||||
TEST(GeckoProfiler, Markers)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
profiler_tracing("A", "B", TRACING_EVENT);
|
||||
profiler_tracing("A", "C", TRACING_INTERVAL_START);
|
||||
|
@ -310,7 +289,7 @@ TEST(GeckoProfiler, Markers)
|
|||
|
||||
TEST(GeckoProfiler, Time)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
double t1 = profiler_time();
|
||||
|
@ -319,8 +298,7 @@ TEST(GeckoProfiler, Time)
|
|||
|
||||
// profiler_start() restarts the timer used by profiler_time().
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
double t3 = profiler_time();
|
||||
double t4 = profiler_time();
|
||||
|
@ -335,14 +313,13 @@ TEST(GeckoProfiler, Time)
|
|||
|
||||
TEST(GeckoProfiler, GetProfile)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
ASSERT_TRUE(!profiler_get_profile());
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
UniquePtr<char[]> profile = profiler_get_profile();
|
||||
ASSERT_TRUE(profile && profile[0] == '{');
|
||||
|
@ -354,15 +331,14 @@ TEST(GeckoProfiler, GetProfile)
|
|||
|
||||
TEST(GeckoProfiler, StreamJSONForThisProcess)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
SpliceableChunkedJSONWriter w;
|
||||
ASSERT_TRUE(!profiler_stream_json_for_this_process(w));
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
w.Start(SpliceableJSONWriter::SingleLineStyle);
|
||||
ASSERT_TRUE(profiler_stream_json_for_this_process(w));
|
||||
|
@ -378,7 +354,7 @@ TEST(GeckoProfiler, StreamJSONForThisProcess)
|
|||
|
||||
TEST(GeckoProfiler, PseudoStack)
|
||||
{
|
||||
const char* features[] = { "stackwalk" };
|
||||
uint32_t features = ProfilerFeature::StackWalk;
|
||||
const char* filters[] = { "GeckoMain" };
|
||||
|
||||
PROFILER_LABEL("A", "B", js::ProfileEntry::Category::OTHER);
|
||||
|
@ -390,8 +366,7 @@ TEST(GeckoProfiler, PseudoStack)
|
|||
dynamic.get());
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
filters, MOZ_ARRAY_LENGTH(filters));
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(profiler_get_backtrace());
|
||||
}
|
||||
|
@ -415,23 +390,22 @@ TEST(GeckoProfiler, PseudoStack)
|
|||
|
||||
TEST(GeckoProfiler, Bug1355807)
|
||||
{
|
||||
const char* features[] = { "js" };
|
||||
uint32_t features = ProfilerFeature::JS;
|
||||
const char* manyThreadsFilter[] = { "" };
|
||||
const char* fewThreadsFilter[] = { "GeckoMain" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
features,
|
||||
manyThreadsFilter, MOZ_ARRAY_LENGTH(manyThreadsFilter));
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
features,
|
||||
fewThreadsFilter, MOZ_ARRAY_LENGTH(fewThreadsFilter));
|
||||
|
||||
// In bug 1355807 this caused an assertion failure in StopJSSampling().
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, MOZ_ARRAY_LENGTH(features),
|
||||
features,
|
||||
fewThreadsFilter, MOZ_ARRAY_LENGTH(fewThreadsFilter));
|
||||
|
||||
profiler_stop();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,29 +17,20 @@ ANRReporter::RequestNativeStack(bool aUnwind)
|
|||
// Don't proceed if profiler is already running
|
||||
return false;
|
||||
}
|
||||
|
||||
// WARNING: we are on the ANR reporter thread at this point and it is
|
||||
// generally unsafe to use the profiler from off the main thread. However,
|
||||
// the risk here is limited because for most users, the profiler is not run
|
||||
// elsewhere. See the discussion in Bug 863777, comment 13
|
||||
const char *NATIVE_STACK_FEATURES[] =
|
||||
{"leaf", "threads", "privacy"};
|
||||
const char *NATIVE_STACK_UNWIND_FEATURES[] =
|
||||
{"leaf", "threads", "privacy", "stackwalk"};
|
||||
uint32_t features = ProfilerFeature::Leaf |
|
||||
ProfilerFeature::Privacy |
|
||||
(aUnwind ? ProfilerFeature::StackWalk : 0) |
|
||||
ProfilerFeature::Threads;
|
||||
|
||||
const char **features = NATIVE_STACK_FEATURES;
|
||||
size_t features_size = sizeof(NATIVE_STACK_FEATURES);
|
||||
if (aUnwind) {
|
||||
features = NATIVE_STACK_UNWIND_FEATURES;
|
||||
features_size = sizeof(NATIVE_STACK_UNWIND_FEATURES);
|
||||
// We want the new unwinder if the unwind mode has not been set yet
|
||||
putenv("MOZ_PROFILER_NEW=1");
|
||||
}
|
||||
const char *NATIVE_STACK_THREADS[] = {"GeckoMain", "Compositor"};
|
||||
|
||||
const char *NATIVE_STACK_THREADS[] =
|
||||
{"GeckoMain", "Compositor"};
|
||||
// Buffer one sample and let the profiler wait a long time
|
||||
profiler_start(/* entries */ 100, /* interval */ 10000,
|
||||
features, features_size / sizeof(char*),
|
||||
profiler_start(/* entries */ 100, /* interval */ 10000, features,
|
||||
NATIVE_STACK_THREADS,
|
||||
sizeof(NATIVE_STACK_THREADS) / sizeof(char*));
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче