Bug 1571390 - BlocksRingBuffer::GetState() takes a snapshot of the current state - r=gregtatum

This makes it easier to grab all BlocksRingBuffer state variables:
- Range start and end.
- Number of pushed blocks/entries, number of cleared blocks/entries.

The function is thread-safe, and the returned values are consistent with each
other, but they may become stale straight after the function returns (and the
lock is released).
They are still valuable to statistics, and to know how far the range has at
least reached (but may go further soon).

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gerald Squelart 2019-08-07 01:54:31 +00:00
parent f2af619bd3
commit c05de0f147
2 changed files with 41 additions and 17 deletions

View File

@ -183,12 +183,29 @@ class BlocksRingBuffer {
// Buffer length, constant. No need for locking.
PowerOfTwo<Length> BufferLength() const { return mBuffer.BufferLength(); }
// Number of pushed and cleared entries. Live entries = pushed - cleared.
// Snapshot of the buffer state.
struct State {
// Index to the first block.
BlockIndex mRangeStart;
// Index past the last block. Equals mRangeStart if empty.
BlockIndex mRangeEnd;
// Number of blocks that have been pushed into this buffer.
uint64_t mPushedBlockCount = 0;
// Number of blocks that have been removed from this buffer.
// Note: Live entries = pushed - cleared.
uint64_t mClearedBlockCount = 0;
};
// Get a snapshot of the current state.
// Note that these may change right after this thread-safe call, so they
// should only be used for statistical purposes.
Pair<uint64_t, uint64_t> GetPushedAndClearedCounts() const {
State GetState() const {
baseprofiler::detail::BaseProfilerAutoLock lock(mMutex);
return {mPushedBlockCount, mClearedBlockCount};
return {mFirstReadIndex, mNextWriteIndex, mPushedBlockCount,
mClearedBlockCount};
}
// Iterator-like class used to read from an entry.

View File

@ -465,14 +465,13 @@ void TestBlocksRingBufferAPI() {
lastDestroyed = aReader.ReadObject<uint32_t>();
});
# define VERIFY_START_END_DESTROYED(aStart, aEnd, aLastDestroyed) \
rb.Read([&](const BlocksRingBuffer::Reader aReader) { \
MOZ_RELEASE_ASSERT(ExtractBlockIndex(aReader.BufferRangeStart()) == \
(aStart)); \
MOZ_RELEASE_ASSERT(ExtractBlockIndex(aReader.BufferRangeEnd()) == \
(aEnd)); \
MOZ_RELEASE_ASSERT(lastDestroyed == (aLastDestroyed)); \
});
# define VERIFY_START_END_DESTROYED(aStart, aEnd, aLastDestroyed) \
{ \
BlocksRingBuffer::State state = rb.GetState(); \
MOZ_RELEASE_ASSERT(ExtractBlockIndex(state.mRangeStart) == (aStart)); \
MOZ_RELEASE_ASSERT(ExtractBlockIndex(state.mRangeEnd) == (aEnd)); \
MOZ_RELEASE_ASSERT(lastDestroyed == (aLastDestroyed)); \
}
// All entries will contain one 32-bit number. The resulting blocks will
// have the following structure:
@ -795,12 +794,20 @@ void TestBlocksRingBufferThreading() {
std::atomic<bool> stopReader{false};
std::thread reader([&]() {
for (;;) {
Pair<uint64_t, uint64_t> counts = rb.GetPushedAndClearedCounts();
printf("Reader: pushed=%llu cleared=%llu alive=%llu lastDestroyed=%d\n",
static_cast<unsigned long long>(counts.first()),
static_cast<unsigned long long>(counts.second()),
static_cast<unsigned long long>(counts.first() - counts.second()),
int(lastDestroyed));
BlocksRingBuffer::State state = rb.GetState();
printf(
"Reader: range=%llu..%llu (%llu bytes) pushed=%llu cleared=%llu "
"(alive=%llu) lastDestroyed=%d\n",
static_cast<unsigned long long>(ExtractBlockIndex(state.mRangeStart)),
static_cast<unsigned long long>(ExtractBlockIndex(state.mRangeEnd)),
static_cast<unsigned long long>(ExtractBlockIndex(state.mRangeEnd)) -
static_cast<unsigned long long>(
ExtractBlockIndex(state.mRangeStart)),
static_cast<unsigned long long>(state.mPushedBlockCount),
static_cast<unsigned long long>(state.mClearedBlockCount),
static_cast<unsigned long long>(state.mPushedBlockCount -
state.mClearedBlockCount),
int(lastDestroyed));
if (stopReader) {
break;
}