зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1476757 - Add methods to change the capacity of the ProfileBuffer. r=njn
Depends on D8218 Differential Revision: https://phabricator.services.mozilla.com/D6264 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6a39163ecd
Коммит
b177228e70
|
@ -16,19 +16,14 @@
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
ProfileBuffer::ProfileBuffer(uint32_t aCapacity)
|
ProfileBuffer::ProfileBuffer(uint32_t aCapacity)
|
||||||
: mEntryIndexMask(0)
|
: mEntries(nullptr)
|
||||||
|
, mEntryIndexMask(0)
|
||||||
, mRangeStart(0)
|
, mRangeStart(0)
|
||||||
, mRangeEnd(0)
|
, mRangeEnd(0)
|
||||||
, mCapacity(0)
|
, mCapacity(0)
|
||||||
{
|
{
|
||||||
// Round aCapacity up to the nearest power of two, so that we can index
|
bool succeeded = SetMinCapacity(aCapacity);
|
||||||
// mEntries with a simple mask and don't need to do a slow modulo operation.
|
MOZ_RELEASE_ASSERT(succeeded, "Couldn't allocate initial ProfileBuffer storage");
|
||||||
const uint32_t UINT32_MAX_POWER_OF_TWO = 1 << 31;
|
|
||||||
MOZ_RELEASE_ASSERT(aCapacity <= UINT32_MAX_POWER_OF_TWO,
|
|
||||||
"aCapacity is larger than what we support");
|
|
||||||
mCapacity = RoundUpPow2(aCapacity);
|
|
||||||
mEntryIndexMask = mCapacity - 1;
|
|
||||||
mEntries = MakeUnique<ProfileBufferEntry[]>(mCapacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileBuffer::~ProfileBuffer()
|
ProfileBuffer::~ProfileBuffer()
|
||||||
|
@ -38,6 +33,101 @@ ProfileBuffer::~ProfileBuffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ProfileBuffer::SetMinCapacity(uint32_t aMinCapacity)
|
||||||
|
{
|
||||||
|
// Round aMinCapacity up to the nearest power of two, so that we can index
|
||||||
|
// mEntries with a simple mask and don't need to do a slow modulo operation.
|
||||||
|
const uint32_t UINT32_MAX_POWER_OF_TWO = 1 << 31;
|
||||||
|
MOZ_RELEASE_ASSERT(aMinCapacity <= UINT32_MAX_POWER_OF_TWO,
|
||||||
|
"aMinCapacity is larger than what we support");
|
||||||
|
return SetCapacityPow2(RoundUpPow2(aMinCapacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
RoundDownToMultipleOfPow2(uint64_t aNumber, uint64_t aMultiplier)
|
||||||
|
{
|
||||||
|
return aNumber & ~(aMultiplier - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ProfileBuffer::SetCapacityPow2(uint32_t aNewCapacity)
|
||||||
|
{
|
||||||
|
MOZ_RELEASE_ASSERT(aNewCapacity != 0, "can't set ProfileBuffer capacity to zero");
|
||||||
|
MOZ_RELEASE_ASSERT(IsPowerOfTwo(aNewCapacity), "aNewCapacity needs to be a power of two");
|
||||||
|
|
||||||
|
if (aNewCapacity == mCapacity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_RELEASE_ASSERT(Length() <= aNewCapacity, "can't make the capacity smaller than the used size");
|
||||||
|
|
||||||
|
auto newEntries = MakeUniqueFallible<ProfileBufferEntry[]>(aNewCapacity);
|
||||||
|
if (!newEntries) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t newIndexMask = aNewCapacity - 1;
|
||||||
|
|
||||||
|
if (mCapacity != 0 && mRangeStart != mRangeEnd) {
|
||||||
|
// Copy existing data from mEntries into newEntries. Make sure that every
|
||||||
|
// entry preserves its position in buffer space.
|
||||||
|
// If the range wraps around in the old or in the new buffer, we need to
|
||||||
|
// copy the data in two chunks: [start, wrapIndex), [wrapIndex, end)
|
||||||
|
// If the range wraps in both the old and the new buffer, the wrap index
|
||||||
|
// will be the same in both buffers.
|
||||||
|
//
|
||||||
|
// If range doesn't wrap around:
|
||||||
|
//
|
||||||
|
// +- wrapIndex
|
||||||
|
// |+- mRangeStart
|
||||||
|
// || +- mRangeEnd
|
||||||
|
// vv v
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// | |[---]| | | | | | |
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// | [---] | |
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// ^^^^^^^ smaller capacity
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^ larger capacity
|
||||||
|
//
|
||||||
|
// If range wraps around:
|
||||||
|
//
|
||||||
|
// +- mRangeStart
|
||||||
|
// | +- wrapIndex
|
||||||
|
// | | +- mRangeEnd
|
||||||
|
// v v v
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// | | | | [---+-] | | | |
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// | [---+-] |
|
||||||
|
// ...-+-----+-----+-----+-----+-----+-----+-----+-----+-...
|
||||||
|
// ^^^^^^^ smaller capacity
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^ larger capacity
|
||||||
|
uint64_t wrapIndex =
|
||||||
|
RoundDownToMultipleOfPow2(mRangeEnd, std::min(aNewCapacity, mCapacity));
|
||||||
|
if (wrapIndex <= mRangeStart) {
|
||||||
|
// There is no wrapping. Copy the entire range as one chunk.
|
||||||
|
PodCopy(&newEntries[mRangeStart & newIndexMask],
|
||||||
|
&mEntries[mRangeStart & mEntryIndexMask],
|
||||||
|
mRangeEnd - mRangeStart);
|
||||||
|
} else {
|
||||||
|
// Copy the range in two separate chunks.
|
||||||
|
PodCopy(&newEntries[mRangeStart & newIndexMask],
|
||||||
|
&mEntries[mRangeStart & mEntryIndexMask],
|
||||||
|
wrapIndex - mRangeStart);
|
||||||
|
PodCopy(&newEntries[wrapIndex & newIndexMask],
|
||||||
|
&mEntries[wrapIndex & mEntryIndexMask],
|
||||||
|
mRangeEnd - wrapIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCapacity = aNewCapacity;
|
||||||
|
mEntryIndexMask = newIndexMask;
|
||||||
|
mEntries = std::move(newEntries);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Called from signal, call only reentrant functions
|
// Called from signal, call only reentrant functions
|
||||||
void
|
void
|
||||||
ProfileBuffer::AddEntry(const ProfileBufferEntry& aEntry)
|
ProfileBuffer::AddEntry(const ProfileBufferEntry& aEntry)
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "mozilla/RefCounted.h"
|
#include "mozilla/RefCounted.h"
|
||||||
|
|
||||||
// A fixed-capacity circular buffer.
|
// A resizeable circular buffer.
|
||||||
// This class is used as a queue of entries which, after construction, never
|
// This class is used as a queue of entries which, outside of construction and
|
||||||
// allocates. This makes it safe to use in the profiler's "critical section".
|
// calls to SetCapacity, never allocates. This makes it safe to use in the
|
||||||
|
// profiler's "critical section".
|
||||||
// Entries are appended at the end. Once the queue capacity has been reached,
|
// Entries are appended at the end. Once the queue capacity has been reached,
|
||||||
// adding a new entry will evict an old entry from the start of the queue.
|
// adding a new entry will evict an old entry from the start of the queue.
|
||||||
// Positions in the queue are represented as 64-bit unsigned integers which
|
// Positions in the queue are represented as 64-bit unsigned integers which
|
||||||
|
@ -36,6 +37,19 @@ public:
|
||||||
|
|
||||||
~ProfileBuffer();
|
~ProfileBuffer();
|
||||||
|
|
||||||
|
uint32_t Length() { return mRangeEnd - mRangeStart; }
|
||||||
|
|
||||||
|
// Set the buffer capacity to at least aMinCapacity. aMinCapacity must not be
|
||||||
|
// zero and at least Length(). Otherwise, it triggers abort. This method
|
||||||
|
// allocates. The allocation is fallible and the return value indicates success.
|
||||||
|
bool SetMinCapacity(uint32_t aMinCapacity);
|
||||||
|
|
||||||
|
// Set the buffer capacity to exactly aNewCapacity. aNewCapacity must be a
|
||||||
|
// power of two, non-zero, and at least Length(). Otherwise, it triggers abort.
|
||||||
|
// This method allocates. The allocation is fallible and the return value
|
||||||
|
// indicates success.
|
||||||
|
bool SetCapacityPow2(uint32_t aNewCapacity);
|
||||||
|
|
||||||
// Add |aEntry| to the buffer, ignoring what kind of entry it is.
|
// Add |aEntry| to the buffer, ignoring what kind of entry it is.
|
||||||
void AddEntry(const ProfileBufferEntry& aEntry);
|
void AddEntry(const ProfileBufferEntry& aEntry);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче