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:
Nicholas Nethercote 2017-05-01 14:23:34 +10:00
Родитель cc78872f8c
Коммит ea25e62e3c
23 изменённых файлов: 300 добавлений и 343 удалений

Просмотреть файл

@ -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;