NBLog: Restore log dump and add new logging types
Merging is temporarily disabled for now because the readers managed by
the merger are the same as the ones used for the dumpsys log dump, and
reading from the log effectively consumes the buffer. Eventually, the
readers for the two functionalities will need to be separated to avoid
conflict. The dump of the merged buffer is also disabled, which removes
the dumping of histograms.
The new types added are monotonic thread cycle time, CPU thread cycle
time, CPU frequency, and latency (which will need to be specified in
further detail later). Logging support is added only for monotonic
thread cycle time at the moment.
Test: build, log monotonic thread cycle time in FastThread, check output
in dumpsys media.log -r.
Change-Id: I1b781d6db102fb917fd0bac964eeebd0309234c0
Bug: 68148948
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index bfc797c..f5d2d6d 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -25,6 +25,7 @@
#include <iostream>
#include <math.h>
#include <numeric>
+#include <unordered_set>
#include <vector>
#include <stdarg.h>
#include <stdint.h>
@@ -66,7 +67,9 @@
/*static*/
std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr)
{
- if (ptr == nullptr) return nullptr;
+ if (ptr == nullptr) {
+ return nullptr;
+ }
const uint8_t type = EntryIterator(ptr)->type;
switch (type) {
case EVENT_START_FMT:
@@ -139,10 +142,7 @@
++it; // skip timestamp
++it; // skip hash
// if there is an author entry, return it, return -1 otherwise
- if (it->type == EVENT_AUTHOR) {
- return it.payload<int>();
- }
- return -1;
+ return it->type == EVENT_AUTHOR ? it.payload<int>() : -1;
}
NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
@@ -261,11 +261,8 @@
int NBLog::HistogramEntry::author() const
{
EntryIterator it(mEntry);
- if (it->length == sizeof(HistTsEntryWithAuthor)) {
- return it.payload<HistTsEntryWithAuthor>().author;
- } else {
- return -1;
- }
+ return it->length == sizeof(HistTsEntryWithAuthor)
+ ? it.payload<HistTsEntryWithAuthor>().author : -1;
}
NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
@@ -357,7 +354,9 @@
void NBLog::Writer::log(const char *string)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
size_t length = strlen(string);
if (length > Entry::kMaxLength) {
@@ -368,7 +367,9 @@
void NBLog::Writer::logf(const char *fmt, ...)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
va_list ap;
va_start(ap, fmt);
Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
@@ -377,7 +378,9 @@
void NBLog::Writer::logvf(const char *fmt, va_list ap)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
char buffer[Entry::kMaxLength + 1 /*NUL*/];
int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
if (length >= (int) sizeof(buffer)) {
@@ -392,7 +395,9 @@
void NBLog::Writer::logTimestamp()
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
int64_t ts = get_monotonic_ns();
if (ts > 0) {
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
@@ -403,31 +408,41 @@
void NBLog::Writer::logTimestamp(const int64_t ts)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
}
void NBLog::Writer::logInteger(const int x)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
log(EVENT_INTEGER, &x, sizeof(x));
}
void NBLog::Writer::logFloat(const float x)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
log(EVENT_FLOAT, &x, sizeof(x));
}
void NBLog::Writer::logPID()
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
log(EVENT_PID, mPidTag, mPidTagSize);
}
void NBLog::Writer::logStart(const char *fmt)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
size_t length = strlen(fmt);
if (length > Entry::kMaxLength) {
length = Entry::kMaxLength;
@@ -437,20 +452,26 @@
void NBLog::Writer::logEnd()
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
Entry entry = Entry(EVENT_END_FMT, NULL, 0);
log(entry, true);
}
void NBLog::Writer::logHash(log_hash_t hash)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
log(EVENT_HASH, &hash, sizeof(hash));
}
void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
HistTsEntry data;
data.hash = hash;
data.ts = get_monotonic_ns();
@@ -461,9 +482,19 @@
}
}
+void NBLog::Writer::logMonotonicCycleTime(uint32_t monotonicNs)
+{
+ if (!mEnabled) {
+ return;
+ }
+ log(EVENT_MONOTONIC_CYCLE_TIME, &monotonicNs, sizeof(&monotonicNs));
+}
+
void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
va_list ap;
va_start(ap, hash);
Writer::logVFormat(fmt, hash, ap);
@@ -472,7 +503,9 @@
void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
Writer::logStart(fmt);
int i;
double f;
@@ -528,7 +561,9 @@
void NBLog::Writer::log(Event event, const void *data, size_t length)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
if (data == NULL || length > Entry::kMaxLength) {
// TODO Perhaps it makes sense to display truncated data or at least a
// message that the data is too long? The current behavior can create
@@ -545,13 +580,15 @@
void NBLog::Writer::log(const NBLog::Entry &etr, bool trusted)
{
- if (!mEnabled) return;
+ if (!mEnabled) {
+ return;
+ }
if (!trusted) {
log(etr.mEvent, etr.mData, etr.mLength);
return;
}
- size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
- // need = number of bytes written to FIFO
+ const size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
+ // need = number of bytes written to FIFO
// FIXME optimize this using memcpy for the data part of the Entry.
// The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
@@ -676,15 +713,21 @@
// ---------------------------------------------------------------------------
-const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
+const std::unordered_set<NBLog::Event> NBLog::Reader::startingTypes {
+ NBLog::Event::EVENT_START_FMT,
NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
- NBLog::Event::EVENT_AUDIO_STATE};
-const std::set<NBLog::Event> NBLog::Reader::endingTypes {NBLog::Event::EVENT_END_FMT,
+ NBLog::Event::EVENT_AUDIO_STATE,
+ NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+};
+const std::unordered_set<NBLog::Event> NBLog::Reader::endingTypes {
+ NBLog::Event::EVENT_END_FMT,
NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
- NBLog::Event::EVENT_AUDIO_STATE};
+ NBLog::Event::EVENT_AUDIO_STATE,
+ NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+};
-NBLog::Reader::Reader(const void *shared, size_t size)
- : mFd(-1), mIndent(0), mLost(0),
+NBLog::Reader::Reader(const void *shared, size_t size, const std::string &name)
+ : mFd(-1), mIndent(0), mLost(0), mName(name),
mShared((/*const*/ Shared *) shared), /*mIMemory*/
mFifo(mShared != NULL ?
new audio_utils_fifo(size, sizeof(uint8_t),
@@ -693,8 +736,8 @@
{
}
-NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size)
- : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
+NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
+ : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
{
mIMemory = iMemory;
}
@@ -706,7 +749,7 @@
}
const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
- const std::set<Event> &types) {
+ const std::unordered_set<Event> &types) {
while (back + Entry::kPreviousLengthOffset >= front) {
const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
if (prev < front || prev + prev[offsetof(entry, length)] +
@@ -735,19 +778,38 @@
// This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
// reader index. The index is incremented after handling corruption, to after the last complete
// entry of the buffer
- size_t lost;
+ size_t lost = 0;
audio_utils_iovec iovec[2];
- const ssize_t availToRead = mFifoReader->obtain(iovec, mFifo->capacity(),
- NULL /*timeout*/, &lost);
+ const size_t capacity = mFifo->capacity();
+ ssize_t availToRead;
+ // A call to audio_utils_fifo_reader::obtain() places the read pointer one buffer length
+ // before the writer's pointer (since mFifoReader was constructed with flush=false). The
+ // do while loop is an attempt to read all of the FIFO's contents regardless of how behind
+ // the reader is with respect to the writer. However, the following scheduling sequence is
+ // possible and can lead to a starvation situation:
+ // - Writer T1 writes, overrun with respect to Reader T2
+ // - T2 calls obtain() and gets EOVERFLOW, T2 ptr placed one buffer size behind T1 ptr
+ // - T1 write, overrun
+ // - T2 obtain(), EOVERFLOW (and so on...)
+ // To address this issue, we limit the number of tries for the reader to catch up with
+ // the writer.
+ int tries = 0;
+ size_t lostTemp;
+ do {
+ availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lostTemp);
+ lost += lostTemp;
+ } while (availToRead < 0 || ++tries <= kMaxObtainTries);
+
if (availToRead <= 0) {
- return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
+ ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
+ return std::make_unique<NBLog::Reader::Snapshot>();
}
std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
if (iovec[1].mLength > 0) {
memcpy(snapshot->mData + (iovec[0].mLength),
- (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
+ (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
}
// Handle corrupted buffer
@@ -857,10 +919,60 @@
ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
}
+void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
+{
+ mFd = fd;
+ mIndent = indent;
+ String8 timestamp, body;
+
+ // Range-based for loop isn't used here because handleFormat() returns an EntryIterator
+ // that points to the next entry (it handles all of the necessary operator++() calls).
+ for (auto entry = snapshot.begin(); entry != snapshot.end();) {
+ switch (entry->type) {
+ case EVENT_START_FMT:
+ entry = handleFormat(FormatEntry(entry), ×tamp, &body);
+ break;
+ case EVENT_HISTOGRAM_ENTRY_TS:
+ ++entry;
+ break;
+ case EVENT_AUDIO_STATE:
+ ++entry;
+ break;
+ case EVENT_END_FMT:
+ body.appendFormat("warning: got to end format event");
+ ++entry;
+ break;
+ case EVENT_MONOTONIC_CYCLE_TIME: {
+ uint32_t monotonicNs = *(uint32_t *) (entry->data);
+ body.appendFormat("Thread cycle took %u ns", monotonicNs);
+ ++entry;
+ } break;
+ case EVENT_RESERVED:
+ default:
+ body.appendFormat("warning: unexpected event %d", entry->type);
+ ++entry;
+ break;
+ }
+ // FIXME: decide whether to print the warnings here or elsewhere
+ if (!body.isEmpty()) {
+ dumpLine(×tamp, &body);
+ }
+ }
+}
+
+void NBLog::Reader::dump(int fd, size_t indent)
+{
+ // get a snapshot, dump it
+ std::unique_ptr<Snapshot> snap = getSnapshot();
+ dump(fd, indent, *snap);
+}
+
// Writes a string to the console
void NBLog::Reader::dumpLine(const String8 *timestamp, String8 *body)
{
- if (timestamp == nullptr || body == nullptr) return;
+ if (timestamp == nullptr || body == nullptr) {
+ return;
+ }
if (mFd >= 0) {
dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp->string(), body->string());
} else {
@@ -878,7 +990,9 @@
void NBLog::appendTimestamp(String8 *body, const void *data)
{
- if (body == nullptr || data == nullptr) return;
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
int64_t ts;
memcpy(&ts, data, sizeof(ts));
body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
@@ -887,14 +1001,18 @@
void NBLog::appendInt(String8 *body, const void *data)
{
- if (body == nullptr || data == nullptr) return;
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
int x = *((int*) data);
body->appendFormat("<%d>", x);
}
void NBLog::appendFloat(String8 *body, const void *data)
{
- if (body == nullptr || data == nullptr) return;
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
float f;
memcpy(&f, data, sizeof(f));
body->appendFormat("<%f>", f);
@@ -902,7 +1020,9 @@
void NBLog::appendPID(String8 *body, const void* data, size_t length)
{
- if (body == nullptr || data == nullptr) return;
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
pid_t id = *((pid_t*) data);
char * name = &((char*) data)[sizeof(pid_t)];
body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
@@ -911,7 +1031,9 @@
String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
{
String8 str;
- if (buffer == nullptr) return str;
+ if (buffer == nullptr) {
+ return str;
+ }
str.append("[ ");
for(size_t i = 0; i < size; i++) {
str.appendFormat("%d ", buffer[i]);
@@ -1026,11 +1148,11 @@
{
}
-void NBLog::Merger::addReader(const NBLog::NamedReader &reader)
+void NBLog::Merger::addReader(const sp<NBLog::Reader> &reader)
{
// FIXME This is called by binder thread in MediaLogService::registerWriter
- // but the access to shared variable mNamedReaders is not yet protected by a lock.
- mNamedReaders.push_back(reader);
+ // but the access to shared variable mReaders is not yet protected by a lock.
+ mReaders.push_back(reader);
}
// items placed in priority queue during merge
@@ -1052,12 +1174,12 @@
{
// FIXME This is called by merge thread
// but the access to shared variable mNamedReaders is not yet protected by a lock.
- const int nLogs = mNamedReaders.size();
+ const int nLogs = mReaders.size();
std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
std::vector<EntryIterator> offsets;
offsets.reserve(nLogs);
for (int i = 0; i < nLogs; ++i) {
- snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
+ snapshots[i] = mReaders[i]->getSnapshot();
offsets.push_back(snapshots[i]->begin());
}
// initialize offsets
@@ -1089,16 +1211,16 @@
}
}
-const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const
+const std::vector<sp<NBLog::Reader>>& NBLog::Merger::getReaders() const
{
- // FIXME This is returning a reference to a shared variable that needs a lock
- return mNamedReaders;
+ //AutoMutex _l(mLock);
+ return mReaders;
}
// ---------------------------------------------------------------------------
NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
- : Reader(shared, size), mNamedReaders(merger.getNamedReaders())
+ : Reader(shared, size, "MergeReader"), mReaders(merger.getReaders())
{
}
@@ -1109,7 +1231,7 @@
return;
}
// FIXME Needs a lock
- const char* name = mNamedReaders[author].name();
+ const char* name = mReaders[author]->name().c_str();
body->appendFormat("%s: ", name);
}
@@ -1142,6 +1264,7 @@
doMerge = mTimeoutUs > 0;
mTimeoutUs -= kThreadSleepPeriodUs;
}
+ doMerge = false; // Disable merging for now.
if (doMerge) {
// Merge data from all the readers
mMerger.merge();
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index bee3ad3..71941a4 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -21,7 +21,7 @@
#include <deque>
#include <map>
-#include <set>
+#include <unordered_set>
#include <vector>
#include <audio_utils/fifo.h>
@@ -64,6 +64,12 @@
EVENT_AUDIO_STATE, // audio on/off event: logged on FastMixer::onStateChange call
EVENT_END_FMT, // end of logFormat argument list
+ // Types representing audio performance metrics
+ EVENT_LATENCY, // TODO classify specifically what this is
+ EVENT_CPU_FREQUENCY, // instantaneous CPU frequency in kHz
+ EVENT_MONOTONIC_CYCLE_TIME, // thread per-cycle monotonic time
+ EVENT_CPU_CYCLE_TIME, // thread per-cycle cpu time
+
EVENT_UPPER_BOUND, // to check for invalid events
};
@@ -200,7 +206,6 @@
// copy entry, adding author before timestamp, returns size of original entry
virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
int author) const override;
-
};
class HistogramEntry : public AbstractEntry {
@@ -217,13 +222,13 @@
virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
int author) const override;
-
};
// ---------------------------------------------------------------------------
// representation of a single log entry in private memory
- struct Entry {
+ class Entry {
+ public:
Entry(Event event, const void *data, size_t length)
: mEvent(event), mLength(length), mData(data) { }
/*virtual*/ ~Entry() { }
@@ -345,12 +350,15 @@
virtual void logInteger(const int x);
virtual void logFloat(const float x);
virtual void logPID();
- virtual void logFormat(const char *fmt, log_hash_t hash, ...);
- virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
virtual void logStart(const char *fmt);
virtual void logEnd();
virtual void logHash(log_hash_t hash);
+ // The functions below are not in LockedWriter yet.
+ virtual void logFormat(const char *fmt, log_hash_t hash, ...);
+ virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
virtual void logEventHistTs(Event event, log_hash_t hash);
+ virtual void logMonotonicCycleTime(uint32_t monotonicNs);
+ // End of functions that are not in LockedWriter yet.
virtual bool isEnabled() const;
@@ -447,16 +455,22 @@
// Input parameter 'size' is the desired size of the timeline in byte units.
// The size of the shared memory must be at least Timeline::sharedSize(size).
- Reader(const void *shared, size_t size);
- Reader(const sp<IMemory>& iMemory, size_t size);
+ Reader(const void *shared, size_t size, const std::string &name);
+ Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name);
virtual ~Reader();
// get snapshot of readers fifo buffer, effectively consuming the buffer
std::unique_ptr<Snapshot> getSnapshot();
+ // dump a particular snapshot of the reader
+ void dump(int fd, size_t indent, Snapshot &snap);
+ // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
+ void dump(int fd, size_t indent = 0);
bool isIMemory(const sp<IMemory>& iMemory) const;
+ const std::string &name() const { return mName; }
+
protected:
// print a summary of the performance to the console
void dumpLine(const String8 *timestamp, String8 *body);
@@ -466,10 +480,12 @@
int mFd; // file descriptor
int mIndent; // indentation level
int mLost; // bytes of data lost before buffer was read
+ const std::string mName; // name of reader (actually name of writer)
+ static constexpr int kMaxObtainTries = 3;
private:
- static const std::set<Event> startingTypes;
- static const std::set<Event> endingTypes;
+ static const std::unordered_set<Event> startingTypes;
+ static const std::unordered_set<Event> endingTypes;
// declared as const because audio_utils_fifo() constructor
sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
@@ -483,29 +499,12 @@
// Searches for the last entry of type <type> in the range [front, back)
// back has to be entry-aligned. Returns nullptr if none enconuntered.
static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
- const std::set<Event> &types);
+ const std::unordered_set<Event> &types);
// dummy method for handling absent author entry
virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
};
- // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
- class NamedReader {
- public:
- NamedReader() { mName[0] = '\0'; } // for Vector
- NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
- mReader(reader)
- { strlcpy(mName, name, sizeof(mName)); }
- ~NamedReader() { }
- const sp<NBLog::Reader>& reader() const { return mReader; }
- const char* name() const { return mName; }
-
- private:
- sp<NBLog::Reader> mReader;
- static const size_t kMaxName = 32;
- char mName[kMaxName];
- };
-
// ---------------------------------------------------------------------------
// This class is used to read data from each thread's individual FIFO in shared memory
@@ -516,18 +515,18 @@
virtual ~Merger() {}
- void addReader(const NamedReader &reader);
+ void addReader(const sp<NBLog::Reader> &reader);
// TODO add removeReader
void merge();
// FIXME This is returning a reference to a shared variable that needs a lock
- const std::vector<NamedReader>& getNamedReaders() const;
+ const std::vector<sp<Reader>>& getReaders() const;
private:
// vector of the readers the merger is supposed to merge from.
// every reader reads from a writer's buffer
// FIXME Needs to be protected by a lock
- std::vector<NamedReader> mNamedReaders;
+ std::vector<sp<Reader>> mReaders;
Shared * const mShared; // raw pointer to shared memory
std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
@@ -535,7 +534,7 @@
};
// This class has a pointer to the FIFO in local memory which stores the merged
- // data collected by NBLog::Merger from all NamedReaders. It is used to process
+ // data collected by NBLog::Merger from all Readers. It is used to process
// this data and write the result to PerformanceAnalysis.
class MergeReader : public Reader {
public:
@@ -550,7 +549,8 @@
private:
// FIXME Needs to be protected by a lock,
// because even though our use of it is read-only there may be asynchronous updates
- const std::vector<NamedReader>& mNamedReaders;
+ // The object is owned by the Merger class.
+ const std::vector<sp<Reader>>& mReaders;
// analyzes, compresses and stores the merged data
// contains a separate instance for every author (thread), and for every source file