зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1023461 - Add HangStack class to support internal string buffer; r=vladan
This commit is contained in:
Родитель
20218b8f58
Коммит
be24a3cd37
|
@ -2066,7 +2066,7 @@ CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const Telemetry::HangHistogram::Stack& hangStack = hang.GetStack();
|
||||
const Telemetry::HangStack& hangStack = hang.GetStack();
|
||||
JS::RootedObject stack(cx,
|
||||
JS_NewArrayObject(cx, hangStack.length()));
|
||||
if (!ret) {
|
||||
|
@ -3027,15 +3027,63 @@ TimeHistogram::Add(PRIntervalTime aTime)
|
|||
operator[](index)++;
|
||||
}
|
||||
|
||||
const char*
|
||||
HangStack::InfallibleAppendViaBuffer(const char* aText, size_t aLength)
|
||||
{
|
||||
MOZ_ASSERT(this->canAppendWithoutRealloc(1));
|
||||
// Include null-terminator in length count.
|
||||
MOZ_ASSERT(mBuffer.canAppendWithoutRealloc(aLength + 1));
|
||||
|
||||
const char* const entry = mBuffer.end();
|
||||
mBuffer.infallibleAppend(aText, aLength);
|
||||
mBuffer.infallibleAppend('\0'); // Explicitly append null-terminator
|
||||
this->infallibleAppend(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
const char*
|
||||
HangStack::AppendViaBuffer(const char* aText, size_t aLength)
|
||||
{
|
||||
if (!this->reserve(this->length() + 1)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Keep track of the previous buffer in case we need to adjust pointers later.
|
||||
const char* const prevStart = mBuffer.begin();
|
||||
const char* const prevEnd = mBuffer.end();
|
||||
|
||||
// Include null-terminator in length count.
|
||||
if (!mBuffer.reserve(mBuffer.length() + aLength + 1)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (prevStart != mBuffer.begin()) {
|
||||
// The buffer has moved; we have to adjust pointers in the stack.
|
||||
for (const char** entry = this->begin(); entry != this->end(); entry++) {
|
||||
if (*entry >= prevStart && *entry < prevEnd) {
|
||||
// Move from old buffer to new buffer.
|
||||
*entry += mBuffer.begin() - prevStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return InfallibleAppendViaBuffer(aText, aLength);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
HangHistogram::GetHash(const Stack& aStack)
|
||||
HangHistogram::GetHash(const HangStack& aStack)
|
||||
{
|
||||
uint32_t hash = 0;
|
||||
for (const char* const* label = aStack.begin();
|
||||
label != aStack.end(); label++) {
|
||||
/* We only need to hash the pointer instead of the text content
|
||||
because we are assuming constant pointers */
|
||||
hash = AddToHash(hash, *label);
|
||||
/* If the string is within our buffer, we need to hash its content.
|
||||
Otherwise, the string is statically allocated, and we only need
|
||||
to hash the pointer instead of the content. */
|
||||
if (aStack.IsInBuffer(*label)) {
|
||||
hash = AddToHash(hash, HashString(*label));
|
||||
} else {
|
||||
hash = AddToHash(hash, *label);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
@ -3049,7 +3097,7 @@ HangHistogram::operator==(const HangHistogram& aOther) const
|
|||
if (mStack.length() != aOther.mStack.length()) {
|
||||
return false;
|
||||
}
|
||||
return PodEqual(mStack.begin(), aOther.mStack.begin(), mStack.length());
|
||||
return mStack == aOther.mStack;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,22 +44,82 @@ public:
|
|||
void Add(PRIntervalTime aTime);
|
||||
};
|
||||
|
||||
/* HangStack stores an array of const char pointers,
|
||||
with optional internal storage for strings. */
|
||||
class HangStack : public mozilla::Vector<const char*, 8>
|
||||
{
|
||||
private:
|
||||
typedef mozilla::Vector<const char*, 8> Base;
|
||||
|
||||
// Stack entries can either be a static const char*
|
||||
// or a pointer to within this buffer.
|
||||
mozilla::Vector<char, 0> mBuffer;
|
||||
|
||||
public:
|
||||
HangStack() { }
|
||||
|
||||
HangStack(HangStack&& aOther)
|
||||
: Base(mozilla::Move(aOther))
|
||||
, mBuffer(mozilla::Move(aOther.mBuffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const HangStack& aOther) const {
|
||||
for (size_t i = 0; i < length(); i++) {
|
||||
if (!IsSameAsEntry(operator[](i), aOther[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const HangStack& aOther) const {
|
||||
return !operator==(aOther);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Base::clear();
|
||||
mBuffer.clear();
|
||||
}
|
||||
|
||||
bool IsInBuffer(const char* aEntry) const {
|
||||
return aEntry >= mBuffer.begin() && aEntry < mBuffer.end();
|
||||
}
|
||||
|
||||
bool IsSameAsEntry(const char* aEntry, const char* aOther) const {
|
||||
// If the entry came from the buffer, we need to compare its content;
|
||||
// otherwise we only need to compare its pointer.
|
||||
return IsInBuffer(aEntry) ? !strcmp(aEntry, aOther) : (aEntry == aOther);
|
||||
}
|
||||
|
||||
size_t AvailableBufferSize() const {
|
||||
return mBuffer.capacity() - mBuffer.length();
|
||||
}
|
||||
|
||||
bool EnsureBufferCapacity(size_t aCapacity) {
|
||||
// aCapacity is the minimal capacity and Vector may make the actual
|
||||
// capacity larger, in which case we want to use up all the space.
|
||||
return mBuffer.reserve(aCapacity) &&
|
||||
mBuffer.reserve(mBuffer.capacity());
|
||||
}
|
||||
|
||||
const char* InfallibleAppendViaBuffer(const char* aText, size_t aLength);
|
||||
const char* AppendViaBuffer(const char* aText, size_t aLength);
|
||||
};
|
||||
|
||||
/* A hang histogram consists of a stack associated with the
|
||||
hang, along with a time histogram of the hang times. */
|
||||
class HangHistogram : public TimeHistogram
|
||||
{
|
||||
public:
|
||||
typedef mozilla::Vector<const char*, 8> Stack;
|
||||
|
||||
private:
|
||||
static uint32_t GetHash(const Stack& aStack);
|
||||
static uint32_t GetHash(const HangStack& aStack);
|
||||
|
||||
Stack mStack;
|
||||
HangStack mStack;
|
||||
// Use a hash to speed comparisons
|
||||
const uint32_t mHash;
|
||||
|
||||
public:
|
||||
explicit HangHistogram(Stack&& aStack)
|
||||
explicit HangHistogram(HangStack&& aStack)
|
||||
: mStack(mozilla::Move(aStack))
|
||||
, mHash(GetHash(mStack))
|
||||
{
|
||||
|
@ -75,7 +135,7 @@ public:
|
|||
{
|
||||
return !operator==(aOther);
|
||||
}
|
||||
const Stack& GetStack() const {
|
||||
const HangStack& GetStack() const {
|
||||
return mStack;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -137,7 +137,7 @@ public:
|
|||
// Platform-specific helper to get hang stacks
|
||||
ThreadStackHelper mStackHelper;
|
||||
// Stack of current hang
|
||||
Telemetry::HangHistogram::Stack mHangStack;
|
||||
Telemetry::HangStack mHangStack;
|
||||
// Statistics for telemetry
|
||||
Telemetry::ThreadHangStats mStats;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace mozilla {
|
|||
class ThreadStackHelper
|
||||
{
|
||||
public:
|
||||
typedef Telemetry::HangHistogram::Stack Stack;
|
||||
typedef Telemetry::HangStack Stack;
|
||||
|
||||
private:
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
|
|
Загрузка…
Ссылка в новой задаче