Loading media/libnblog/NBLog.cpp +181 −58 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <iostream> #include <math.h> #include <numeric> #include <unordered_set> #include <vector> #include <stdarg.h> #include <stdint.h> Loading Loading @@ -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: Loading Loading @@ -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( Loading Loading @@ -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( Loading Loading @@ -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) { Loading @@ -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 Loading @@ -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)) { Loading @@ -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)); Loading @@ -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; Loading @@ -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(); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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 Loading @@ -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. Loading Loading @@ -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), Loading @@ -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; } Loading @@ -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)] + Loading Loading @@ -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)); Loading Loading @@ -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), ×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 { Loading @@ -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)), Loading @@ -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); Loading @@ -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); Loading @@ -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]); Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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()) { } Loading @@ -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); } Loading Loading @@ -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(); Loading media/libnblog/include/media/nblog/NBLog.h +33 −33 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ #include <deque> #include <map> #include <set> #include <unordered_set> #include <vector> #include <audio_utils/fifo.h> Loading Loading @@ -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 }; Loading Loading @@ -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 { Loading @@ -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() { } Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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: Loading @@ -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 Loading services/audioflinger/AudioFlinger.h +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <deque> #include <map> #include <memory> #include <set> #include <string> #include <vector> #include <stdint.h> Loading services/audioflinger/FastThread.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/audioflinger/TypedLogger.h +5 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
media/libnblog/NBLog.cpp +181 −58 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <iostream> #include <math.h> #include <numeric> #include <unordered_set> #include <vector> #include <stdarg.h> #include <stdint.h> Loading Loading @@ -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: Loading Loading @@ -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( Loading Loading @@ -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( Loading Loading @@ -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) { Loading @@ -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 Loading @@ -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)) { Loading @@ -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)); Loading @@ -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; Loading @@ -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(); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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 Loading @@ -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. Loading Loading @@ -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), Loading @@ -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; } Loading @@ -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)] + Loading Loading @@ -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)); Loading Loading @@ -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), ×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 { Loading @@ -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)), Loading @@ -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); Loading @@ -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); Loading @@ -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]); Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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()) { } Loading @@ -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); } Loading Loading @@ -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(); Loading
media/libnblog/include/media/nblog/NBLog.h +33 −33 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ #include <deque> #include <map> #include <set> #include <unordered_set> #include <vector> #include <audio_utils/fifo.h> Loading Loading @@ -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 }; Loading Loading @@ -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 { Loading @@ -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() { } Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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: Loading @@ -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 Loading
services/audioflinger/AudioFlinger.h +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <deque> #include <map> #include <memory> #include <set> #include <string> #include <vector> #include <stdint.h> Loading
services/audioflinger/FastThread.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/audioflinger/TypedLogger.h +5 −0 Original line number Diff line number Diff line Loading @@ -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