Bug 1576555 - Remove unneeded ProfilerMarker - r=gregtatum

Now that what was in ProfilerMarker is stored directly in `BlocksRingBuffer`,
there is no need for this class anymore!
This also removes all the pointer management around it (when added to a TLS
list, moved during sampling, deleted when expired).

Differential Revision: https://phabricator.services.mozilla.com/D43431

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gerald Squelart 2019-09-17 01:53:50 +00:00
parent 8364b4ebdb
commit 79e1b2e357
14 changed files with 3 additions and 540 deletions

View File

@ -10,8 +10,6 @@
# include "ProfileBuffer.h"
# include "ProfilerMarker.h"
# include "mozilla/MathAlgorithms.h"
namespace mozilla {
@ -37,9 +35,6 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
}
ProfileBuffer::~ProfileBuffer() {
while (mStoredMarkers.peek()) {
delete mStoredMarkers.popHead();
}
// Only ProfileBuffer controls this buffer, and it should be empty when there
// is no ProfileBuffer using it.
mEntries.Reset();
@ -80,11 +75,6 @@ uint64_t ProfileBuffer::AddThreadIdEntry(int aThreadId) {
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
}
void ProfileBuffer::AddMarker(ProfilerMarker* aMarker) {
aMarker->SetPositionInBuffer(AddEntry(ProfileBufferEntry::Marker(aMarker)));
mStoredMarkers.insert(aMarker);
}
void ProfileBuffer::CollectCodeLocation(
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
@ -122,22 +112,10 @@ void ProfileBuffer::CollectCodeLocation(
}
}
void ProfileBuffer::DeleteExpiredStoredMarkers() {
AUTO_PROFILER_STATS(base_ProfileBuffer_DeleteExpiredStoredMarkers);
// Delete markers of samples that have been overwritten due to circular
// buffer wraparound.
while (mStoredMarkers.peek() &&
mStoredMarkers.peek()->HasExpired(BufferRangeStart())) {
delete mStoredMarkers.popHead();
}
}
size_t ProfileBuffer::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
// Measurement of the following members may be added later if DMD finds it
// is worthwhile:
// - memory pointed to by the elements within mEntries
// - mStoredMarkers
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
}

View File

@ -7,7 +7,6 @@
#define MOZ_PROFILE_BUFFER_H
#include "ProfileBufferEntry.h"
#include "ProfilerMarker.h"
#include "mozilla/BlocksRingBuffer.h"
#include "mozilla/Maybe.h"
@ -89,11 +88,6 @@ class ProfileBuffer final {
void DiscardSamplesBeforeTime(double aTime);
void AddMarker(ProfilerMarker* aMarker);
// The following method is not signal safe!
void DeleteExpiredStoredMarkers();
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
@ -141,9 +135,6 @@ class ProfileBuffer final {
return mEntries.GetState().mRangeEnd.ConvertToU64();
}
// Markers that marker entries in the buffer might refer to.
ProfilerMarkerLinkedList mStoredMarkers;
private:
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
const UniquePtr<BlocksRingBuffer::Byte[]> mDuplicationBuffer;

View File

@ -10,6 +10,7 @@
# include "ProfileBufferEntry.h"
# include "BaseProfilerMarkerPayload.h"
# include "platform.h"
# include "ProfileBuffer.h"
@ -43,11 +44,6 @@ ProfileBufferEntry::ProfileBufferEntry(Kind aKind, void* aPtr) : mKind(aKind) {
memcpy(mStorage, &aPtr, sizeof(aPtr));
}
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker)
: mKind(aKind) {
memcpy(mStorage, &aMarker, sizeof(aMarker));
}
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
: mKind(aKind) {
memcpy(mStorage, &aDouble, sizeof(aDouble));
@ -79,12 +75,6 @@ void* ProfileBufferEntry::GetPtr() const {
return result;
}
ProfilerMarker* ProfileBufferEntry::GetMarker() const {
ProfilerMarker* result;
memcpy(&result, mStorage, sizeof(result));
return result;
}
double ProfileBufferEntry::GetDouble() const {
double result;
memcpy(&result, mStorage, sizeof(result));
@ -788,16 +778,6 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter,
sample.mStack = aUniqueStacks.GetOrAddStackIndex(stack);
// Skip over the markers. We process them in StreamMarkersToJSON().
while (e.Has()) {
MOZ_ASSERT(!e.Get().IsMarker());
if (e.Get().IsMarker()) {
e.Next();
} else {
break;
}
}
if (e.Has() && e.Get().IsResponsiveness()) {
sample.mResponsiveness = Some(e.Get().GetDouble());
e.Next();
@ -821,8 +801,6 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
ProfileBufferEntry::Kind::MODERN_LIMIT));
if (type == ProfileBufferEntry::Kind::MarkerData &&
aER.ReadObject<int>() == aThreadId) {
// Adapted from ProfilerMarker::StreamJSON()
// Schema:
// [name, time, category, data]
@ -1259,7 +1237,6 @@ bool ProfileBuffer::DuplicateLastSample(int aThreadId,
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
.ToMilliseconds()));
break;
case ProfileBufferEntry::Kind::Marker:
case ProfileBufferEntry::Kind::CounterKey:
case ProfileBufferEntry::Kind::Number:
case ProfileBufferEntry::Kind::Count:

View File

@ -23,8 +23,6 @@
namespace mozilla {
namespace baseprofiler {
class ProfilerMarker;
// NOTE! If you add entries, you need to verify if they need to be added to the
// switch statement in DuplicateLastSample!
// This will evaluate the MACRO with (KIND, TYPE, SIZE)
@ -39,7 +37,6 @@ class ProfilerMarker;
MACRO(LineNumber, int, sizeof(int)) \
MACRO(ColumnNumber, int, sizeof(int)) \
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
MACRO(Marker, ProfilerMarker*, sizeof(ProfilerMarker*)) \
MACRO(Pause, double, sizeof(double)) \
MACRO(Responsiveness, double, sizeof(double)) \
MACRO(Resume, double, sizeof(double)) \
@ -95,7 +92,6 @@ class ProfileBufferEntry {
ProfileBufferEntry(Kind aKind, const char* aString);
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
ProfileBufferEntry(Kind aKind, void* aPtr);
ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker);
ProfileBufferEntry(Kind aKind, double aDouble);
ProfileBufferEntry(Kind aKind, int64_t aInt64);
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
@ -129,7 +125,6 @@ class ProfileBufferEntry {
const char* GetString() const;
void* GetPtr() const;
ProfilerMarker* GetMarker() const;
double GetDouble() const;
int GetInt() const;
int64_t GetInt64() const;

View File

@ -1,175 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ProfilerMarker_h
#define ProfilerMarker_h
#include "ProfileBufferEntry.h"
#include "BaseProfileJSONWriter.h"
#include "BaseProfilerMarkerPayload.h"
#include "mozilla/UniquePtrExtensions.h"
namespace mozilla {
namespace baseprofiler {
template <typename T>
class ProfilerLinkedList;
class ProfilerMarker {
friend class ProfilerLinkedList<ProfilerMarker>;
public:
explicit ProfilerMarker(const char* aMarkerName,
ProfilingCategoryPair aCategoryPair, int aThreadId,
UniquePtr<ProfilerMarkerPayload> aPayload = nullptr,
double aTime = 0)
: mMarkerName(strdup(aMarkerName)),
mPayload(std::move(aPayload)),
mNext{nullptr},
mTime(aTime),
mPositionInBuffer{0},
mThreadId{aThreadId},
mCategoryPair{aCategoryPair} {}
void SetPositionInBuffer(uint64_t aPosition) {
mPositionInBuffer = aPosition;
}
bool HasExpired(uint64_t aBufferRangeStart) const {
return mPositionInBuffer < aBufferRangeStart;
}
double GetTime() const { return mTime; }
int GetThreadId() const { return mThreadId; }
void StreamJSON(SpliceableJSONWriter& aWriter,
const TimeStamp& aProcessStartTime,
UniqueStacks& aUniqueStacks) const {
// Schema:
// [name, time, category, data]
aWriter.StartArrayElement();
{
aUniqueStacks.mUniqueStrings->WriteElement(aWriter, mMarkerName.get());
aWriter.DoubleElement(mTime);
const ProfilingCategoryPairInfo& info =
GetProfilingCategoryPairInfo(mCategoryPair);
aWriter.IntElement(unsigned(info.mCategory));
// TODO: Store the callsite for this marker if available:
// if have location data
// b.NameValue(marker, "location", ...);
if (mPayload) {
aWriter.StartObjectElement(SpliceableJSONWriter::SingleLineStyle);
{ mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks); }
aWriter.EndObject();
}
}
aWriter.EndArray();
}
private:
UniqueFreePtr<char> mMarkerName;
UniquePtr<ProfilerMarkerPayload> mPayload;
ProfilerMarker* mNext;
double mTime;
uint64_t mPositionInBuffer;
int mThreadId;
ProfilingCategoryPair mCategoryPair;
};
template <typename T>
class ProfilerLinkedList {
public:
ProfilerLinkedList() : mHead(nullptr), mTail(nullptr) {}
void insert(T* aElem) {
if (!mTail) {
mHead = aElem;
mTail = aElem;
} else {
mTail->mNext = aElem;
mTail = aElem;
}
aElem->mNext = nullptr;
}
T* popHead() {
if (!mHead) {
MOZ_ASSERT(false);
return nullptr;
}
T* head = mHead;
mHead = head->mNext;
if (!mHead) {
mTail = nullptr;
}
return head;
}
const T* peek() { return mHead; }
private:
T* mHead;
T* mTail;
};
typedef ProfilerLinkedList<ProfilerMarker> ProfilerMarkerLinkedList;
template <typename T>
class ProfilerSignalSafeLinkedList {
public:
ProfilerSignalSafeLinkedList() : mSignalLock(false) {}
~ProfilerSignalSafeLinkedList() {
if (mSignalLock) {
// Some thread is modifying the list. We should only be released on that
// thread.
abort();
}
while (mList.peek()) {
delete mList.popHead();
}
}
// Insert an item into the list. Must only be called from the owning thread.
// Must not be called while the list from accessList() is being accessed.
// In the profiler, we ensure that by interrupting the profiled thread
// (which is the one that owns this list and calls insert() on it) until
// we're done reading the list from the signal handler.
void insert(T* aElement) {
MOZ_ASSERT(aElement);
mSignalLock = true;
mList.insert(aElement);
mSignalLock = false;
}
// Called within signal, from any thread, possibly while insert() is in the
// middle of modifying the list (on the owning thread). Will return null if
// that is the case.
// Function must be reentrant.
ProfilerLinkedList<T>* accessList() { return mSignalLock ? nullptr : &mList; }
private:
ProfilerLinkedList<T> mList;
// If this is set, then it's not safe to read the list because its contents
// are being changed.
Atomic<bool> mSignalLock;
};
} // namespace baseprofiler
} // namespace mozilla
#endif // ProfilerMarker_h

View File

@ -8,8 +8,6 @@
#define RegisteredThread_h
#include "platform.h"
#include "ProfilerMarker.h"
#include "BaseProfilerMarkerPayload.h"
#include "ThreadInfo.h"
#include "mozilla/UniquePtr.h"
@ -35,25 +33,6 @@ class RacyRegisteredThread final {
bool IsBeingProfiled() const { return mIsBeingProfiled; }
void AddPendingMarker(const char* aMarkerName,
ProfilingCategoryPair aCategoryPair,
UniquePtr<ProfilerMarkerPayload> aPayload,
double aTime) {
// Note: We don't assert on mIsBeingProfiled, because it could have changed
// between the check in the caller and now.
ProfilerMarker* marker = new ProfilerMarker(
aMarkerName, aCategoryPair, mThreadId, std::move(aPayload), aTime);
mPendingMarkers.insert(marker);
}
// Called within signal. Function must be reentrant.
ProfilerMarkerLinkedList* GetPendingMarkers() {
// The profiled thread is interrupted, so we can access the list safely.
// Unless the profiled thread was in the middle of changing the list when
// we interrupted it - in that case, accessList() will return null.
return mPendingMarkers.accessList();
}
// This is called on every profiler restart. Put things that should happen at
// that time here.
void ReinitializeOnResume() {
@ -103,9 +82,6 @@ class RacyRegisteredThread final {
private:
class ProfilingStack mProfilingStack;
// A list of pending markers that must be moved to the circular buffer.
ProfilerSignalSafeLinkedList<ProfilerMarker> mPendingMarkers;
// mThreadId contains the thread ID of the current thread. It is safe to read
// this from multiple threads concurrently, as it will never be mutated.
const int mThreadId;

View File

@ -1473,13 +1473,6 @@ static void DoPeriodicSample(PSLockRef aLock,
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
aSamplePos, aBuffer);
ProfilerMarkerLinkedList* pendingMarkersList =
aRegisteredThread.RacyRegisteredThread().GetPendingMarkers();
while (pendingMarkersList && pendingMarkersList->peek()) {
ProfilerMarker* marker = pendingMarkersList->popHead();
aBuffer.AddMarker(marker);
}
}
// END sampling/unwinding code
@ -1992,7 +1985,6 @@ void SamplerThread::Run() {
ActivePS::ClearExpiredExitProfiles(lock);
ActivePS::Buffer(lock).DeleteExpiredStoredMarkers();
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
if (!ActivePS::IsPaused(lock)) {

View File

@ -6,8 +6,6 @@
#include "ProfileBuffer.h"
#include "ProfilerMarker.h"
#include "BaseProfiler.h"
#include "jsfriendapi.h"
#include "mozilla/MathAlgorithms.h"
@ -36,9 +34,6 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
}
ProfileBuffer::~ProfileBuffer() {
while (mStoredMarkers.peek()) {
delete mStoredMarkers.popHead();
}
// Only ProfileBuffer controls this buffer, and it should be empty when there
// is no ProfileBuffer using it.
mEntries.Reset();
@ -79,11 +74,6 @@ uint64_t ProfileBuffer::AddThreadIdEntry(int aThreadId) {
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
}
void ProfileBuffer::AddMarker(ProfilerMarker* aMarker) {
aMarker->SetPositionInBuffer(AddEntry(ProfileBufferEntry::Marker(aMarker)));
mStoredMarkers.insert(aMarker);
}
void ProfileBuffer::CollectCodeLocation(
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
@ -121,22 +111,10 @@ void ProfileBuffer::CollectCodeLocation(
}
}
void ProfileBuffer::DeleteExpiredStoredMarkers() {
AUTO_PROFILER_STATS(gecko_ProfileBuffer_DeleteExpiredStoredMarkers);
// Delete markers of samples that have been overwritten due to circular
// buffer wraparound.
while (mStoredMarkers.peek() &&
mStoredMarkers.peek()->HasExpired(BufferRangeStart())) {
delete mStoredMarkers.popHead();
}
}
size_t ProfileBuffer::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
// Measurement of the following members may be added later if DMD finds it
// is worthwhile:
// - memory pointed to by the elements within mEntries
// - mStoredMarkers
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
}

View File

@ -6,8 +6,8 @@
#ifndef MOZ_PROFILE_BUFFER_H
#define MOZ_PROFILE_BUFFER_H
#include "GeckoProfiler.h"
#include "ProfileBufferEntry.h"
#include "ProfilerMarker.h"
#include "mozilla/BlocksRingBuffer.h"
#include "mozilla/Maybe.h"
@ -98,11 +98,6 @@ class ProfileBuffer final {
void DiscardSamplesBeforeTime(double aTime);
void AddMarker(ProfilerMarker* aMarker);
// The following method is not signal safe!
void DeleteExpiredStoredMarkers();
// Read an entry in the buffer. Slow!
ProfileBufferEntry GetEntry(uint64_t aPosition) const {
ProfileBufferEntry entry;
@ -173,9 +168,6 @@ class ProfileBuffer final {
return mEntries.GetState().mRangeEnd.ConvertToU64();
}
// Markers that marker entries in the buffer might refer to.
ProfilerMarkerLinkedList mStoredMarkers;
private:
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
mozilla::UniquePtr<mozilla::BlocksRingBuffer::Byte[]> mDuplicationBuffer;

View File

@ -8,6 +8,7 @@
#include "platform.h"
#include "ProfileBuffer.h"
#include "ProfilerMarkerPayload.h"
#include "js/TrackedOptimizationInfo.h"
#include "jsapi.h"
@ -46,11 +47,6 @@ ProfileBufferEntry::ProfileBufferEntry(Kind aKind, void* aPtr) : mKind(aKind) {
memcpy(mStorage, &aPtr, sizeof(aPtr));
}
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker)
: mKind(aKind) {
memcpy(mStorage, &aMarker, sizeof(aMarker));
}
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
: mKind(aKind) {
memcpy(mStorage, &aDouble, sizeof(aDouble));
@ -82,12 +78,6 @@ void* ProfileBufferEntry::GetPtr() const {
return result;
}
ProfilerMarker* ProfileBufferEntry::GetMarker() const {
ProfilerMarker* result;
memcpy(&result, mStorage, sizeof(result));
return result;
}
double ProfileBufferEntry::GetDouble() const {
double result;
memcpy(&result, mStorage, sizeof(result));
@ -1124,16 +1114,6 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter,
sample.mStack = aUniqueStacks.GetOrAddStackIndex(stack);
// Skip over the markers. We process them in StreamMarkersToJSON().
while (e.Has()) {
MOZ_ASSERT(!e.Get().IsMarker());
if (e.Get().IsMarker()) {
e.Next();
} else {
break;
}
}
if (e.Has() && e.Get().IsResponsiveness()) {
sample.mResponsiveness = Some(e.Get().GetDouble());
e.Next();
@ -1206,8 +1186,6 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
ProfileBufferEntry::Kind::MODERN_LIMIT));
if (type == ProfileBufferEntry::Kind::MarkerData &&
aER.ReadObject<int>() == aThreadId) {
// Adapted from ProfilerMarker::StreamJSON()
// Schema:
// [name, time, category, data]
@ -1652,7 +1630,6 @@ bool ProfileBuffer::DuplicateLastSample(int aThreadId,
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
.ToMilliseconds()));
break;
case ProfileBufferEntry::Kind::Marker:
case ProfileBufferEntry::Kind::CounterKey:
case ProfileBufferEntry::Kind::Number:
case ProfileBufferEntry::Kind::Count:

View File

@ -22,7 +22,6 @@
#include "nsString.h"
class ProfilerCodeAddressService;
class ProfilerMarker;
// NOTE! If you add entries, you need to verify if they need to be added to the
// switch statement in DuplicateLastSample!
@ -38,7 +37,6 @@ class ProfilerMarker;
MACRO(LineNumber, int, sizeof(int)) \
MACRO(ColumnNumber, int, sizeof(int)) \
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
MACRO(Marker, ProfilerMarker*, sizeof(ProfilerMarker*)) \
MACRO(Pause, double, sizeof(double)) \
MACRO(Responsiveness, double, sizeof(double)) \
MACRO(Resume, double, sizeof(double)) \
@ -94,7 +92,6 @@ class ProfileBufferEntry {
ProfileBufferEntry(Kind aKind, const char* aString);
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
ProfileBufferEntry(Kind aKind, void* aPtr);
ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker);
ProfileBufferEntry(Kind aKind, double aDouble);
ProfileBufferEntry(Kind aKind, int64_t aInt64);
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
@ -128,7 +125,6 @@ class ProfileBufferEntry {
const char* GetString() const;
void* GetPtr() const;
ProfilerMarker* GetMarker() const;
double GetDouble() const;
int GetInt() const;
int64_t GetInt64() const;

View File

@ -1,180 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ProfilerMarker_h
#define ProfilerMarker_h
#include "ProfileBufferEntry.h"
#include "ProfileJSONWriter.h"
#include "ProfilerMarkerPayload.h"
#include "mozilla/UniquePtrExtensions.h"
template <typename T>
class ProfilerLinkedList;
class ProfilerMarker {
friend class ProfilerLinkedList<ProfilerMarker>;
public:
explicit ProfilerMarker(
const char* aMarkerName, JS::ProfilingCategoryPair aCategoryPair,
int aThreadId,
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload = nullptr,
double aTime = 0)
: mMarkerName(strdup(aMarkerName)),
mPayload(std::move(aPayload)),
mNext{nullptr},
mTime(aTime),
mPositionInBuffer{0},
mThreadId{aThreadId},
mCategoryPair{aCategoryPair} {}
void SetPositionInBuffer(uint64_t aPosition) {
mPositionInBuffer = aPosition;
}
bool HasExpired(uint64_t aBufferRangeStart) const {
return mPositionInBuffer < aBufferRangeStart;
}
double GetTime() const { return mTime; }
int GetThreadId() const { return mThreadId; }
void StreamJSON(SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aProcessStartTime,
UniqueStacks& aUniqueStacks) const {
// Schema:
// [name, time, category, data]
aWriter.StartArrayElement();
{
aUniqueStacks.mUniqueStrings->WriteElement(aWriter, mMarkerName.get());
aWriter.DoubleElement(mTime);
const JS::ProfilingCategoryPairInfo& info =
JS::GetProfilingCategoryPairInfo(mCategoryPair);
aWriter.IntElement(unsigned(info.mCategory));
// TODO: Store the callsite for this marker if available:
// if have location data
// b.NameValue(marker, "location", ...);
if (mPayload) {
aWriter.StartObjectElement(SpliceableJSONWriter::SingleLineStyle);
{ mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks); }
aWriter.EndObject();
}
}
aWriter.EndArray();
}
private:
mozilla::UniqueFreePtr<char> mMarkerName;
mozilla::UniquePtr<ProfilerMarkerPayload> mPayload;
ProfilerMarker* mNext;
double mTime;
uint64_t mPositionInBuffer;
int mThreadId;
JS::ProfilingCategoryPair mCategoryPair;
};
template <typename T>
class ProfilerLinkedList {
public:
ProfilerLinkedList() : mHead(nullptr), mTail(nullptr) {}
void insert(T* aElem) {
if (!mTail) {
mHead = aElem;
mTail = aElem;
} else {
mTail->mNext = aElem;
mTail = aElem;
}
aElem->mNext = nullptr;
}
T* popHead() {
if (!mHead) {
MOZ_ASSERT(false);
return nullptr;
}
T* head = mHead;
mHead = head->mNext;
if (!mHead) {
mTail = nullptr;
}
return head;
}
const T* peek() { return mHead; }
private:
T* mHead;
T* mTail;
};
typedef ProfilerLinkedList<ProfilerMarker> ProfilerMarkerLinkedList;
template <typename T>
class ProfilerSignalSafeLinkedList {
public:
ProfilerSignalSafeLinkedList() : mSignalLock(false) {}
~ProfilerSignalSafeLinkedList() {
if (mSignalLock) {
// Some thread is modifying the list. We should only be released on that
// thread.
abort();
}
reset();
}
// Reset the list of pending signals in this list.
// We assume that this is called at a time when it is
// guaranteed that no more than a single user (the caller)
// is accessing the list. In particular, it is only
// called from within the RacyRegisteredThread::ReinitializeOnResume
// method.
void reset() {
while (mList.peek()) {
delete mList.popHead();
}
}
// Insert an item into the list. Must only be called from the owning thread.
// Must not be called while the list from accessList() is being accessed.
// In the profiler, we ensure that by interrupting the profiled thread
// (which is the one that owns this list and calls insert() on it) until
// we're done reading the list from the signal handler.
void insert(T* aElement) {
MOZ_ASSERT(aElement);
mSignalLock = true;
mList.insert(aElement);
mSignalLock = false;
}
// Called within signal, from any thread, possibly while insert() is in the
// middle of modifying the list (on the owning thread). Will return null if
// that is the case.
// Function must be reentrant.
ProfilerLinkedList<T>* accessList() { return mSignalLock ? nullptr : &mList; }
private:
ProfilerLinkedList<T> mList;
// If this is set, then it's not safe to read the list because its contents
// are being changed.
mozilla::Atomic<bool> mSignalLock;
};
#endif // ProfilerMarker_h

View File

@ -8,8 +8,6 @@
#define RegisteredThread_h
#include "platform.h"
#include "ProfilerMarker.h"
#include "ProfilerMarkerPayload.h"
#include "ThreadInfo.h"
#include "js/TraceLoggerAPI.h"
@ -37,30 +35,9 @@ class RacyRegisteredThread final {
bool IsBeingProfiled() const { return mIsBeingProfiled; }
void AddPendingMarker(const char* aMarkerName,
JS::ProfilingCategoryPair aCategoryPair,
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload,
double aTime) {
// Note: We don't assert on mIsBeingProfiled, because it could have changed
// between the check in the caller and now.
ProfilerMarker* marker = new ProfilerMarker(
aMarkerName, aCategoryPair, mThreadId, std::move(aPayload), aTime);
mPendingMarkers.insert(marker);
}
// Called within signal. Function must be reentrant.
ProfilerMarkerLinkedList* GetPendingMarkers() {
// The profiled thread is interrupted, so we can access the list safely.
// Unless the profiled thread was in the middle of changing the list when
// we interrupted it - in that case, accessList() will return null.
return mPendingMarkers.accessList();
}
// This is called on every profiler restart. Put things that should happen at
// that time here.
void ReinitializeOnResume() {
mPendingMarkers.reset();
// This is needed to cause an initial sample to be taken from sleeping
// threads that had been observed prior to the profiler stopping and
// restarting. Otherwise sleeping threads would not have any samples to
@ -107,9 +84,6 @@ class RacyRegisteredThread final {
private:
class ProfilingStack mProfilingStack;
// A list of pending markers that must be moved to the circular buffer.
ProfilerSignalSafeLinkedList<ProfilerMarker> mPendingMarkers;
// mThreadId contains the thread ID of the current thread. It is safe to read
// this from multiple threads concurrently, as it will never be mutated.
const int mThreadId;

View File

@ -1756,13 +1756,6 @@ static void DoPeriodicSample(PSLockRef aLock,
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
aSamplePos, aBuffer);
ProfilerMarkerLinkedList* pendingMarkersList =
aRegisteredThread.RacyRegisteredThread().GetPendingMarkers();
while (pendingMarkersList && pendingMarkersList->peek()) {
ProfilerMarker* marker = pendingMarkersList->popHead();
aBuffer.AddMarker(marker);
}
ThreadResponsiveness* resp = aProfiledThreadData.GetThreadResponsiveness();
if (resp && resp->HasData()) {
double delta = resp->GetUnresponsiveDuration(
@ -2550,7 +2543,6 @@ void SamplerThread::Run() {
ActivePS::ClearExpiredExitProfiles(lock);
ActivePS::Buffer(lock).DeleteExpiredStoredMarkers();
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
if (!ActivePS::IsPaused(lock)) {