зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
02d2886883
Коммит
58ac06a047
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
# include "ProfileBuffer.h"
|
# include "ProfileBuffer.h"
|
||||||
|
|
||||||
# include "ProfilerMarker.h"
|
|
||||||
|
|
||||||
# include "mozilla/MathAlgorithms.h"
|
# include "mozilla/MathAlgorithms.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -37,9 +35,6 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileBuffer::~ProfileBuffer() {
|
ProfileBuffer::~ProfileBuffer() {
|
||||||
while (mStoredMarkers.peek()) {
|
|
||||||
delete mStoredMarkers.popHead();
|
|
||||||
}
|
|
||||||
// Only ProfileBuffer controls this buffer, and it should be empty when there
|
// Only ProfileBuffer controls this buffer, and it should be empty when there
|
||||||
// is no ProfileBuffer using it.
|
// is no ProfileBuffer using it.
|
||||||
mEntries.Reset();
|
mEntries.Reset();
|
||||||
|
@ -80,11 +75,6 @@ uint64_t ProfileBuffer::AddThreadIdEntry(int aThreadId) {
|
||||||
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
|
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileBuffer::AddMarker(ProfilerMarker* aMarker) {
|
|
||||||
aMarker->SetPositionInBuffer(AddEntry(ProfileBufferEntry::Marker(aMarker)));
|
|
||||||
mStoredMarkers.insert(aMarker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileBuffer::CollectCodeLocation(
|
void ProfileBuffer::CollectCodeLocation(
|
||||||
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
||||||
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
|
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 {
|
size_t ProfileBuffer::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
||||||
// Measurement of the following members may be added later if DMD finds it
|
// Measurement of the following members may be added later if DMD finds it
|
||||||
// is worthwhile:
|
// is worthwhile:
|
||||||
// - memory pointed to by the elements within mEntries
|
// - memory pointed to by the elements within mEntries
|
||||||
// - mStoredMarkers
|
|
||||||
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
|
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#define MOZ_PROFILE_BUFFER_H
|
#define MOZ_PROFILE_BUFFER_H
|
||||||
|
|
||||||
#include "ProfileBufferEntry.h"
|
#include "ProfileBufferEntry.h"
|
||||||
#include "ProfilerMarker.h"
|
|
||||||
|
|
||||||
#include "mozilla/BlocksRingBuffer.h"
|
#include "mozilla/BlocksRingBuffer.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
|
@ -89,11 +88,6 @@ class ProfileBuffer final {
|
||||||
|
|
||||||
void DiscardSamplesBeforeTime(double aTime);
|
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 SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||||
|
|
||||||
|
@ -141,9 +135,6 @@ class ProfileBuffer final {
|
||||||
return mEntries.GetState().mRangeEnd.ConvertToU64();
|
return mEntries.GetState().mRangeEnd.ConvertToU64();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Markers that marker entries in the buffer might refer to.
|
|
||||||
ProfilerMarkerLinkedList mStoredMarkers;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
|
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
|
||||||
const UniquePtr<BlocksRingBuffer::Byte[]> mDuplicationBuffer;
|
const UniquePtr<BlocksRingBuffer::Byte[]> mDuplicationBuffer;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
# include "ProfileBufferEntry.h"
|
# include "ProfileBufferEntry.h"
|
||||||
|
|
||||||
|
# include "BaseProfilerMarkerPayload.h"
|
||||||
# include "platform.h"
|
# include "platform.h"
|
||||||
# include "ProfileBuffer.h"
|
# include "ProfileBuffer.h"
|
||||||
|
|
||||||
|
@ -43,11 +44,6 @@ ProfileBufferEntry::ProfileBufferEntry(Kind aKind, void* aPtr) : mKind(aKind) {
|
||||||
memcpy(mStorage, &aPtr, sizeof(aPtr));
|
memcpy(mStorage, &aPtr, sizeof(aPtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker)
|
|
||||||
: mKind(aKind) {
|
|
||||||
memcpy(mStorage, &aMarker, sizeof(aMarker));
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
|
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
|
||||||
: mKind(aKind) {
|
: mKind(aKind) {
|
||||||
memcpy(mStorage, &aDouble, sizeof(aDouble));
|
memcpy(mStorage, &aDouble, sizeof(aDouble));
|
||||||
|
@ -79,12 +75,6 @@ void* ProfileBufferEntry::GetPtr() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilerMarker* ProfileBufferEntry::GetMarker() const {
|
|
||||||
ProfilerMarker* result;
|
|
||||||
memcpy(&result, mStorage, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ProfileBufferEntry::GetDouble() const {
|
double ProfileBufferEntry::GetDouble() const {
|
||||||
double result;
|
double result;
|
||||||
memcpy(&result, mStorage, sizeof(result));
|
memcpy(&result, mStorage, sizeof(result));
|
||||||
|
@ -788,16 +778,6 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter,
|
||||||
|
|
||||||
sample.mStack = aUniqueStacks.GetOrAddStackIndex(stack);
|
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()) {
|
if (e.Has() && e.Get().IsResponsiveness()) {
|
||||||
sample.mResponsiveness = Some(e.Get().GetDouble());
|
sample.mResponsiveness = Some(e.Get().GetDouble());
|
||||||
e.Next();
|
e.Next();
|
||||||
|
@ -821,8 +801,6 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
|
||||||
ProfileBufferEntry::Kind::MODERN_LIMIT));
|
ProfileBufferEntry::Kind::MODERN_LIMIT));
|
||||||
if (type == ProfileBufferEntry::Kind::MarkerData &&
|
if (type == ProfileBufferEntry::Kind::MarkerData &&
|
||||||
aER.ReadObject<int>() == aThreadId) {
|
aER.ReadObject<int>() == aThreadId) {
|
||||||
// Adapted from ProfilerMarker::StreamJSON()
|
|
||||||
|
|
||||||
// Schema:
|
// Schema:
|
||||||
// [name, time, category, data]
|
// [name, time, category, data]
|
||||||
|
|
||||||
|
@ -1259,7 +1237,6 @@ bool ProfileBuffer::DuplicateLastSample(int aThreadId,
|
||||||
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
|
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
|
||||||
.ToMilliseconds()));
|
.ToMilliseconds()));
|
||||||
break;
|
break;
|
||||||
case ProfileBufferEntry::Kind::Marker:
|
|
||||||
case ProfileBufferEntry::Kind::CounterKey:
|
case ProfileBufferEntry::Kind::CounterKey:
|
||||||
case ProfileBufferEntry::Kind::Number:
|
case ProfileBufferEntry::Kind::Number:
|
||||||
case ProfileBufferEntry::Kind::Count:
|
case ProfileBufferEntry::Kind::Count:
|
||||||
|
|
|
@ -23,8 +23,6 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace baseprofiler {
|
namespace baseprofiler {
|
||||||
|
|
||||||
class ProfilerMarker;
|
|
||||||
|
|
||||||
// NOTE! If you add entries, you need to verify if they need to be added to the
|
// NOTE! If you add entries, you need to verify if they need to be added to the
|
||||||
// switch statement in DuplicateLastSample!
|
// switch statement in DuplicateLastSample!
|
||||||
// This will evaluate the MACRO with (KIND, TYPE, SIZE)
|
// This will evaluate the MACRO with (KIND, TYPE, SIZE)
|
||||||
|
@ -39,7 +37,6 @@ class ProfilerMarker;
|
||||||
MACRO(LineNumber, int, sizeof(int)) \
|
MACRO(LineNumber, int, sizeof(int)) \
|
||||||
MACRO(ColumnNumber, int, sizeof(int)) \
|
MACRO(ColumnNumber, int, sizeof(int)) \
|
||||||
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
|
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
|
||||||
MACRO(Marker, ProfilerMarker*, sizeof(ProfilerMarker*)) \
|
|
||||||
MACRO(Pause, double, sizeof(double)) \
|
MACRO(Pause, double, sizeof(double)) \
|
||||||
MACRO(Responsiveness, double, sizeof(double)) \
|
MACRO(Responsiveness, double, sizeof(double)) \
|
||||||
MACRO(Resume, double, sizeof(double)) \
|
MACRO(Resume, double, sizeof(double)) \
|
||||||
|
@ -95,7 +92,6 @@ class ProfileBufferEntry {
|
||||||
ProfileBufferEntry(Kind aKind, const char* aString);
|
ProfileBufferEntry(Kind aKind, const char* aString);
|
||||||
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
|
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
|
||||||
ProfileBufferEntry(Kind aKind, void* aPtr);
|
ProfileBufferEntry(Kind aKind, void* aPtr);
|
||||||
ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker);
|
|
||||||
ProfileBufferEntry(Kind aKind, double aDouble);
|
ProfileBufferEntry(Kind aKind, double aDouble);
|
||||||
ProfileBufferEntry(Kind aKind, int64_t aInt64);
|
ProfileBufferEntry(Kind aKind, int64_t aInt64);
|
||||||
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
|
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
|
||||||
|
@ -129,7 +125,6 @@ class ProfileBufferEntry {
|
||||||
|
|
||||||
const char* GetString() const;
|
const char* GetString() const;
|
||||||
void* GetPtr() const;
|
void* GetPtr() const;
|
||||||
ProfilerMarker* GetMarker() const;
|
|
||||||
double GetDouble() const;
|
double GetDouble() const;
|
||||||
int GetInt() const;
|
int GetInt() const;
|
||||||
int64_t GetInt64() const;
|
int64_t GetInt64() const;
|
||||||
|
|
|
@ -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
|
|
|
@ -8,8 +8,6 @@
|
||||||
#define RegisteredThread_h
|
#define RegisteredThread_h
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "ProfilerMarker.h"
|
|
||||||
#include "BaseProfilerMarkerPayload.h"
|
|
||||||
#include "ThreadInfo.h"
|
#include "ThreadInfo.h"
|
||||||
|
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
|
@ -35,25 +33,6 @@ class RacyRegisteredThread final {
|
||||||
|
|
||||||
bool IsBeingProfiled() const { return mIsBeingProfiled; }
|
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
|
// This is called on every profiler restart. Put things that should happen at
|
||||||
// that time here.
|
// that time here.
|
||||||
void ReinitializeOnResume() {
|
void ReinitializeOnResume() {
|
||||||
|
@ -103,9 +82,6 @@ class RacyRegisteredThread final {
|
||||||
private:
|
private:
|
||||||
class ProfilingStack mProfilingStack;
|
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
|
// 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.
|
// this from multiple threads concurrently, as it will never be mutated.
|
||||||
const int mThreadId;
|
const int mThreadId;
|
||||||
|
|
|
@ -1473,13 +1473,6 @@ static void DoPeriodicSample(PSLockRef aLock,
|
||||||
|
|
||||||
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
|
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
|
||||||
aSamplePos, aBuffer);
|
aSamplePos, aBuffer);
|
||||||
|
|
||||||
ProfilerMarkerLinkedList* pendingMarkersList =
|
|
||||||
aRegisteredThread.RacyRegisteredThread().GetPendingMarkers();
|
|
||||||
while (pendingMarkersList && pendingMarkersList->peek()) {
|
|
||||||
ProfilerMarker* marker = pendingMarkersList->popHead();
|
|
||||||
aBuffer.AddMarker(marker);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// END sampling/unwinding code
|
// END sampling/unwinding code
|
||||||
|
@ -1992,7 +1985,6 @@ void SamplerThread::Run() {
|
||||||
|
|
||||||
ActivePS::ClearExpiredExitProfiles(lock);
|
ActivePS::ClearExpiredExitProfiles(lock);
|
||||||
|
|
||||||
ActivePS::Buffer(lock).DeleteExpiredStoredMarkers();
|
|
||||||
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
|
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
|
||||||
|
|
||||||
if (!ActivePS::IsPaused(lock)) {
|
if (!ActivePS::IsPaused(lock)) {
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
#include "ProfileBuffer.h"
|
#include "ProfileBuffer.h"
|
||||||
|
|
||||||
#include "ProfilerMarker.h"
|
|
||||||
|
|
||||||
#include "BaseProfiler.h"
|
#include "BaseProfiler.h"
|
||||||
#include "js/GCAPI.h"
|
#include "js/GCAPI.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
|
@ -37,9 +35,6 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileBuffer::~ProfileBuffer() {
|
ProfileBuffer::~ProfileBuffer() {
|
||||||
while (mStoredMarkers.peek()) {
|
|
||||||
delete mStoredMarkers.popHead();
|
|
||||||
}
|
|
||||||
// Only ProfileBuffer controls this buffer, and it should be empty when there
|
// Only ProfileBuffer controls this buffer, and it should be empty when there
|
||||||
// is no ProfileBuffer using it.
|
// is no ProfileBuffer using it.
|
||||||
mEntries.Reset();
|
mEntries.Reset();
|
||||||
|
@ -83,11 +78,6 @@ uint64_t ProfileBuffer::AddThreadIdEntry(int aThreadId) {
|
||||||
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
|
return AddThreadIdEntry(mEntries, aThreadId).ConvertToU64();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileBuffer::AddMarker(ProfilerMarker* aMarker) {
|
|
||||||
aMarker->SetPositionInBuffer(AddEntry(ProfileBufferEntry::Marker(aMarker)));
|
|
||||||
mStoredMarkers.insert(aMarker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfileBuffer::CollectCodeLocation(
|
void ProfileBuffer::CollectCodeLocation(
|
||||||
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
||||||
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
|
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
|
||||||
|
@ -125,22 +115,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 {
|
size_t ProfileBuffer::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
||||||
// Measurement of the following members may be added later if DMD finds it
|
// Measurement of the following members may be added later if DMD finds it
|
||||||
// is worthwhile:
|
// is worthwhile:
|
||||||
// - memory pointed to by the elements within mEntries
|
// - memory pointed to by the elements within mEntries
|
||||||
// - mStoredMarkers
|
|
||||||
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
|
return mEntries.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#ifndef MOZ_PROFILE_BUFFER_H
|
#ifndef MOZ_PROFILE_BUFFER_H
|
||||||
#define MOZ_PROFILE_BUFFER_H
|
#define MOZ_PROFILE_BUFFER_H
|
||||||
|
|
||||||
|
#include "GeckoProfiler.h"
|
||||||
#include "ProfileBufferEntry.h"
|
#include "ProfileBufferEntry.h"
|
||||||
#include "ProfilerMarker.h"
|
|
||||||
|
|
||||||
#include "mozilla/BlocksRingBuffer.h"
|
#include "mozilla/BlocksRingBuffer.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
|
@ -98,11 +98,6 @@ class ProfileBuffer final {
|
||||||
|
|
||||||
void DiscardSamplesBeforeTime(double aTime);
|
void DiscardSamplesBeforeTime(double aTime);
|
||||||
|
|
||||||
void AddMarker(ProfilerMarker* aMarker);
|
|
||||||
|
|
||||||
// The following method is not signal safe!
|
|
||||||
void DeleteExpiredStoredMarkers();
|
|
||||||
|
|
||||||
// Read an entry in the buffer. Slow!
|
// Read an entry in the buffer. Slow!
|
||||||
ProfileBufferEntry GetEntry(uint64_t aPosition) const {
|
ProfileBufferEntry GetEntry(uint64_t aPosition) const {
|
||||||
ProfileBufferEntry entry;
|
ProfileBufferEntry entry;
|
||||||
|
@ -173,9 +168,6 @@ class ProfileBuffer final {
|
||||||
return mEntries.GetState().mRangeEnd.ConvertToU64();
|
return mEntries.GetState().mRangeEnd.ConvertToU64();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Markers that marker entries in the buffer might refer to.
|
|
||||||
ProfilerMarkerLinkedList mStoredMarkers;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
|
// Used when duplicating sleeping stacks (to avoid spurious mallocs).
|
||||||
mozilla::UniquePtr<mozilla::BlocksRingBuffer::Byte[]> mDuplicationBuffer;
|
mozilla::UniquePtr<mozilla::BlocksRingBuffer::Byte[]> mDuplicationBuffer;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "ProfileBuffer.h"
|
#include "ProfileBuffer.h"
|
||||||
|
#include "ProfilerMarkerPayload.h"
|
||||||
|
|
||||||
#include "js/TrackedOptimizationInfo.h"
|
#include "js/TrackedOptimizationInfo.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
@ -46,11 +47,6 @@ ProfileBufferEntry::ProfileBufferEntry(Kind aKind, void* aPtr) : mKind(aKind) {
|
||||||
memcpy(mStorage, &aPtr, sizeof(aPtr));
|
memcpy(mStorage, &aPtr, sizeof(aPtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker)
|
|
||||||
: mKind(aKind) {
|
|
||||||
memcpy(mStorage, &aMarker, sizeof(aMarker));
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
|
ProfileBufferEntry::ProfileBufferEntry(Kind aKind, double aDouble)
|
||||||
: mKind(aKind) {
|
: mKind(aKind) {
|
||||||
memcpy(mStorage, &aDouble, sizeof(aDouble));
|
memcpy(mStorage, &aDouble, sizeof(aDouble));
|
||||||
|
@ -82,12 +78,6 @@ void* ProfileBufferEntry::GetPtr() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilerMarker* ProfileBufferEntry::GetMarker() const {
|
|
||||||
ProfilerMarker* result;
|
|
||||||
memcpy(&result, mStorage, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ProfileBufferEntry::GetDouble() const {
|
double ProfileBufferEntry::GetDouble() const {
|
||||||
double result;
|
double result;
|
||||||
memcpy(&result, mStorage, sizeof(result));
|
memcpy(&result, mStorage, sizeof(result));
|
||||||
|
@ -1124,16 +1114,6 @@ void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter,
|
||||||
|
|
||||||
sample.mStack = aUniqueStacks.GetOrAddStackIndex(stack);
|
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()) {
|
if (e.Has() && e.Get().IsResponsiveness()) {
|
||||||
sample.mResponsiveness = Some(e.Get().GetDouble());
|
sample.mResponsiveness = Some(e.Get().GetDouble());
|
||||||
e.Next();
|
e.Next();
|
||||||
|
@ -1206,8 +1186,6 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
|
||||||
ProfileBufferEntry::Kind::MODERN_LIMIT));
|
ProfileBufferEntry::Kind::MODERN_LIMIT));
|
||||||
if (type == ProfileBufferEntry::Kind::MarkerData &&
|
if (type == ProfileBufferEntry::Kind::MarkerData &&
|
||||||
aER.ReadObject<int>() == aThreadId) {
|
aER.ReadObject<int>() == aThreadId) {
|
||||||
// Adapted from ProfilerMarker::StreamJSON()
|
|
||||||
|
|
||||||
// Schema:
|
// Schema:
|
||||||
// [name, time, category, data]
|
// [name, time, category, data]
|
||||||
|
|
||||||
|
@ -1652,7 +1630,6 @@ bool ProfileBuffer::DuplicateLastSample(int aThreadId,
|
||||||
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
|
(TimeStamp::NowUnfuzzed() - aProcessStartTime)
|
||||||
.ToMilliseconds()));
|
.ToMilliseconds()));
|
||||||
break;
|
break;
|
||||||
case ProfileBufferEntry::Kind::Marker:
|
|
||||||
case ProfileBufferEntry::Kind::CounterKey:
|
case ProfileBufferEntry::Kind::CounterKey:
|
||||||
case ProfileBufferEntry::Kind::Number:
|
case ProfileBufferEntry::Kind::Number:
|
||||||
case ProfileBufferEntry::Kind::Count:
|
case ProfileBufferEntry::Kind::Count:
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
class ProfilerCodeAddressService;
|
class ProfilerCodeAddressService;
|
||||||
class ProfilerMarker;
|
|
||||||
|
|
||||||
// NOTE! If you add entries, you need to verify if they need to be added to the
|
// NOTE! If you add entries, you need to verify if they need to be added to the
|
||||||
// switch statement in DuplicateLastSample!
|
// switch statement in DuplicateLastSample!
|
||||||
|
@ -38,7 +37,6 @@ class ProfilerMarker;
|
||||||
MACRO(LineNumber, int, sizeof(int)) \
|
MACRO(LineNumber, int, sizeof(int)) \
|
||||||
MACRO(ColumnNumber, int, sizeof(int)) \
|
MACRO(ColumnNumber, int, sizeof(int)) \
|
||||||
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
|
MACRO(NativeLeafAddr, void*, sizeof(void*)) \
|
||||||
MACRO(Marker, ProfilerMarker*, sizeof(ProfilerMarker*)) \
|
|
||||||
MACRO(Pause, double, sizeof(double)) \
|
MACRO(Pause, double, sizeof(double)) \
|
||||||
MACRO(Responsiveness, double, sizeof(double)) \
|
MACRO(Responsiveness, double, sizeof(double)) \
|
||||||
MACRO(Resume, double, sizeof(double)) \
|
MACRO(Resume, double, sizeof(double)) \
|
||||||
|
@ -94,7 +92,6 @@ class ProfileBufferEntry {
|
||||||
ProfileBufferEntry(Kind aKind, const char* aString);
|
ProfileBufferEntry(Kind aKind, const char* aString);
|
||||||
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
|
ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
|
||||||
ProfileBufferEntry(Kind aKind, void* aPtr);
|
ProfileBufferEntry(Kind aKind, void* aPtr);
|
||||||
ProfileBufferEntry(Kind aKind, ProfilerMarker* aMarker);
|
|
||||||
ProfileBufferEntry(Kind aKind, double aDouble);
|
ProfileBufferEntry(Kind aKind, double aDouble);
|
||||||
ProfileBufferEntry(Kind aKind, int64_t aInt64);
|
ProfileBufferEntry(Kind aKind, int64_t aInt64);
|
||||||
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
|
ProfileBufferEntry(Kind aKind, uint64_t aUint64);
|
||||||
|
@ -128,7 +125,6 @@ class ProfileBufferEntry {
|
||||||
|
|
||||||
const char* GetString() const;
|
const char* GetString() const;
|
||||||
void* GetPtr() const;
|
void* GetPtr() const;
|
||||||
ProfilerMarker* GetMarker() const;
|
|
||||||
double GetDouble() const;
|
double GetDouble() const;
|
||||||
int GetInt() const;
|
int GetInt() const;
|
||||||
int64_t GetInt64() const;
|
int64_t GetInt64() const;
|
||||||
|
|
|
@ -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
|
|
|
@ -8,8 +8,6 @@
|
||||||
#define RegisteredThread_h
|
#define RegisteredThread_h
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "ProfilerMarker.h"
|
|
||||||
#include "ProfilerMarkerPayload.h"
|
|
||||||
#include "ThreadInfo.h"
|
#include "ThreadInfo.h"
|
||||||
|
|
||||||
#include "js/TraceLoggerAPI.h"
|
#include "js/TraceLoggerAPI.h"
|
||||||
|
@ -37,30 +35,9 @@ class RacyRegisteredThread final {
|
||||||
|
|
||||||
bool IsBeingProfiled() const { return mIsBeingProfiled; }
|
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
|
// This is called on every profiler restart. Put things that should happen at
|
||||||
// that time here.
|
// that time here.
|
||||||
void ReinitializeOnResume() {
|
void ReinitializeOnResume() {
|
||||||
mPendingMarkers.reset();
|
|
||||||
|
|
||||||
// This is needed to cause an initial sample to be taken from sleeping
|
// This is needed to cause an initial sample to be taken from sleeping
|
||||||
// threads that had been observed prior to the profiler stopping and
|
// threads that had been observed prior to the profiler stopping and
|
||||||
// restarting. Otherwise sleeping threads would not have any samples to
|
// restarting. Otherwise sleeping threads would not have any samples to
|
||||||
|
@ -107,9 +84,6 @@ class RacyRegisteredThread final {
|
||||||
private:
|
private:
|
||||||
class ProfilingStack mProfilingStack;
|
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
|
// 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.
|
// this from multiple threads concurrently, as it will never be mutated.
|
||||||
const int mThreadId;
|
const int mThreadId;
|
||||||
|
|
|
@ -1756,13 +1756,6 @@ static void DoPeriodicSample(PSLockRef aLock,
|
||||||
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
|
DoSharedSample(aLock, /* aIsSynchronous = */ false, aRegisteredThread, aRegs,
|
||||||
aSamplePos, aBuffer);
|
aSamplePos, aBuffer);
|
||||||
|
|
||||||
ProfilerMarkerLinkedList* pendingMarkersList =
|
|
||||||
aRegisteredThread.RacyRegisteredThread().GetPendingMarkers();
|
|
||||||
while (pendingMarkersList && pendingMarkersList->peek()) {
|
|
||||||
ProfilerMarker* marker = pendingMarkersList->popHead();
|
|
||||||
aBuffer.AddMarker(marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadResponsiveness* resp = aProfiledThreadData.GetThreadResponsiveness();
|
ThreadResponsiveness* resp = aProfiledThreadData.GetThreadResponsiveness();
|
||||||
if (resp && resp->HasData()) {
|
if (resp && resp->HasData()) {
|
||||||
double delta = resp->GetUnresponsiveDuration(
|
double delta = resp->GetUnresponsiveDuration(
|
||||||
|
@ -2550,7 +2543,6 @@ void SamplerThread::Run() {
|
||||||
|
|
||||||
ActivePS::ClearExpiredExitProfiles(lock);
|
ActivePS::ClearExpiredExitProfiles(lock);
|
||||||
|
|
||||||
ActivePS::Buffer(lock).DeleteExpiredStoredMarkers();
|
|
||||||
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
|
TimeStamp expiredMarkersCleaned = TimeStamp::NowUnfuzzed();
|
||||||
|
|
||||||
if (!ActivePS::IsPaused(lock)) {
|
if (!ActivePS::IsPaused(lock)) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче