зеркало из 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;
|
||||
|
||||
ProfileBuffer::ProfileBuffer(uint32_t aCapacity)
|
||||
: mEntryIndexMask(0)
|
||||
: mEntries(nullptr)
|
||||
, mEntryIndexMask(0)
|
||||
, mRangeStart(0)
|
||||
, mRangeEnd(0)
|
||||
, mCapacity(0)
|
||||
{
|
||||
// Round aCapacity 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(aCapacity <= UINT32_MAX_POWER_OF_TWO,
|
||||
"aCapacity is larger than what we support");
|
||||
mCapacity = RoundUpPow2(aCapacity);
|
||||
mEntryIndexMask = mCapacity - 1;
|
||||
mEntries = MakeUnique<ProfileBufferEntry[]>(mCapacity);
|
||||
bool succeeded = SetMinCapacity(aCapacity);
|
||||
MOZ_RELEASE_ASSERT(succeeded, "Couldn't allocate initial ProfileBuffer storage");
|
||||
}
|
||||
|
||||
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
|
||||
void
|
||||
ProfileBuffer::AddEntry(const ProfileBufferEntry& aEntry)
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
// A fixed-capacity circular buffer.
|
||||
// This class is used as a queue of entries which, after construction, never
|
||||
// allocates. This makes it safe to use in the profiler's "critical section".
|
||||
// A resizeable circular buffer.
|
||||
// This class is used as a queue of entries which, outside of construction and
|
||||
// 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,
|
||||
// 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
|
||||
|
@ -36,6 +37,19 @@ public:
|
|||
|
||||
~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.
|
||||
void AddEntry(const ProfileBufferEntry& aEntry);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче