Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5786e01d authored by Eric Tan's avatar Eric Tan
Browse files

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
parent 86be8728
Loading
Loading
Loading
Loading
+181 −58
Original line number Diff line number Diff line
@@ -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 @@ int NBLog::Entry::copyEntryDataAt(size_t offset) const
/*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 @@ int NBLog::FormatEntry::author() const
    ++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 @@ NBLog::log_hash_t NBLog::HistogramEntry::hash() const
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 @@ NBLog::Writer::~Writer()

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::log(const char *string)

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::logf(const char *fmt, ...)

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::logvf(const char *fmt, va_list ap)

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()

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::logStart(const char *fmt)

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::logEventHistTs(Event event, log_hash_t hash)
    }
}

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::logFormat(const char *fmt, log_hash_t hash, ...)

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::logVFormat(const char *fmt, log_hash_t hash, va_list argp)

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,12 +580,14 @@ void NBLog::Writer::log(Event event, const void *data, size_t length)

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
    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.
@@ -676,15 +713,21 @@ bool NBLog::LockedWriter::setEnabled(bool enabled)

// ---------------------------------------------------------------------------

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 void *shared, size_t size)
{
}

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 @@ NBLog::Reader::~Reader()
}

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,12 +778,31 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
    // 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));
@@ -857,10 +919,60 @@ void NBLog::MergeReader::dump(int fd, int indent)
    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), &timestamp, &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(&timestamp, &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 @@ bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const

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::appendTimestamp(String8 *body, const void *data)

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::appendFloat(String8 *body, const void *data)

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 @@ void NBLog::appendPID(String8 *body, const void* data, size_t length)
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 @@ NBLog::Merger::Merger(const void *shared, size_t size):
{
}

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 @@ void NBLog::Merger::merge()
{
    // 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 @@ void NBLog::Merger::merge()
    }
}

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 @@ void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8
        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 @@ bool NBLog::MergeThread::threadLoop()
        doMerge = mTimeoutUs > 0;
        mTimeoutUs -= kThreadSleepPeriodUs;
    }
    doMerge = false;    // Disable merging for now.
    if (doMerge) {
        // Merge data from all the readers
        mMerger.merge();
+33 −33
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@

#include <deque>
#include <map>
#include <set>
#include <unordered_set>
#include <vector>

#include <audio_utils/fifo.h>
@@ -64,6 +64,12 @@ public:
        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 @@ private:
        // 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 @@ private:

        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 @@ public:
        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 @@ public:

        // 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 @@ public:
        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 @@ public:
        // 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 @@ public:

        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 @@ public:
    };

    // 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 @@ public:
    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
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <stdint.h>
+1 −0
Original line number Diff line number Diff line
@@ -339,6 +339,7 @@ bool FastThread::threadLoop()
                    // these stores #1, #2, #3 are not atomic with respect to each other,
                    // or with respect to store #4 below
                    mDumpState->mMonotonicNs[i] = monotonicNs;
                    LOG_MONOTONIC_CYCLE_TIME(monotonicNs);
                    mDumpState->mLoadNs[i] = loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
                    mDumpState->mCpukHz[i] = kHz;
+5 −0
Original line number Diff line number Diff line
@@ -97,6 +97,11 @@ constexpr uint64_t hash(const char (&file)[n], uint32_t line) {
#define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
        x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)

// Record a typed entry that represents a thread's cycle time in nanoseconds.
// Parameter ns should be of type uint32_t.
#define LOG_MONOTONIC_CYCLE_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
        x->logMonotonicCycleTime(ns); } while (0)

namespace android {
extern "C" {
extern thread_local NBLog::Writer *tlNBLogWriter;
Loading