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

Commit 66d2ea48 authored by Sanna Catherine de Treville Wager's avatar Sanna Catherine de Treville Wager Committed by Android (Google) Code Review
Browse files

Merge changes I4bbea8b5,Ib60758e1

* changes:
  Write thread and data to separate files
  Separate analysis for each source file location
parents 43be9048 23f89d34
Loading
Loading
Loading
Loading
+15 −14
Original line number Diff line number Diff line
@@ -49,20 +49,25 @@
*
* 2) reading the data from shared memory
* Thread::threadloop()
*     TODO: add description?
* NBLog::MergeThread::threadLoop()
*     calls NBLog::Merger::merge
*     Waits on a mutex, called periodically
*     Calls NBLog::Merger::merge and MergeReader.getAndProcessSnapshot.
* NBLog::Merger::merge
*     Merges snapshots sorted by timestamp
*     for each reader in vector of class NamedReader,
*     callsNamedReader::reader()->getSnapshot
*     TODO: check whether the rest of this function is relevant
*     Calls Reader::getSnapshot on each individual thread buffer to in shared
*     memory and writes all their data to the single FIFO stored in mMerger.
* NBLog::Reader::getSnapshot
*     copies snapshot of reader's fifo buffer into its own buffer
*     calls mFifoReader->obtain to find readable data
*     sets snapshot.begin() and .end() iterators to boundaries of valid entries
*     moves the fifo reader index to after the last entry read
*     in this case, the buffer is in shared memory. in (4), the buffer is private
* NBLog::MergeThread::getAndProcessSnapshot
*     Iterates through the entries in the local FIFO. Processes the data in
*     specific ways depending on the entry type. If the data is a histogram
*     timestamp or an audio on/off signal, writes to a map of PerformanceAnalysis
*     class instances, where the wakeup() intervals are stored as histograms
*     and analyzed.
*
* 3) reading the data from private buffer
* MediaLogService::dump
@@ -876,8 +881,7 @@ std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot)
{
    String8 timestamp, body;
    // TODO: check: is the FIXME below still a problem?
    // FIXME: this is not thread safe
    // TODO: check: is this thread safe?
    // TODO: add lost data information and notification to ReportPerformance
    size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
    if (lost > 0) {
@@ -899,7 +903,7 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot
            memcpy(&hash, &(data->hash), sizeof(hash));
            int64_t ts;
            memcpy(&ts, &data->ts, sizeof(ts));
            mThreadPerformanceAnalysis[data->author].logTsEntry(ts);
            mThreadPerformanceAnalysis[data->author][hash].logTsEntry(ts);
            ++entry;
            break;
        }
@@ -907,12 +911,9 @@ void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Reader::Snapshot &snapshot
            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
            // TODO This memcpies are here to avoid unaligned memory access crash.
            // There's probably a more efficient way to do it
            // TODO: incorporate hash information in mThreadPerformanceAnalysis
            // log_hash_t hash;
            // memcpy(&hash, &(data->hash), sizeof(hash));
            // int64_t ts;
            // memcpy(&ts, &data->ts, sizeof(ts));
            mThreadPerformanceAnalysis[data->author].handleStateChange();
            log_hash_t hash;
            memcpy(&hash, &(data->hash), sizeof(hash));
            mThreadPerformanceAnalysis[data->author][hash].handleStateChange();
            ++entry;
            break;
        }
+16 −10
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ void PerformanceAnalysis::processAndFlushTimeStampSeries() {
        return;
    }

    // mHists is empty if program just started
    // mHists is empty if thread/hash pair is sending data for the first time
    if (mHists.empty()) {
        mHists.emplace_front(static_cast<uint64_t>(mTimeStampSeries[0]),
                            std::map<int, int>());
@@ -130,10 +130,6 @@ void PerformanceAnalysis::logTsEntry(int64_t ts) {
    }
}

// TODO: move this someplace
// static const char* const kName = (const char *) "/data/misc/audioserver/sample_results.txt";
//    writeToFile(mOutlierData, mLongTermHists, kName, false);

// Given a series of outlier intervals (mOutlier data),
// looks for changes in distribution (peaks), which can be either positive or negative.
// The function sets the mean to the starting value and sigma to 0, and updates
@@ -223,7 +219,6 @@ void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> &timestamp
    }
}


// FIXME: delete this temporary test code, recycled for various new functions
void PerformanceAnalysis::testFunction() {
    // produces values (4: 5000000), (13: 18000000)
@@ -241,7 +236,10 @@ void PerformanceAnalysis::testFunction() {
// TODO Make it return a std::string instead of modifying body --> is this still relevant?
// TODO consider changing all ints to uint32_t or uint64_t
// TODO: move this to ReportPerformance, probably make it a friend function of PerformanceAnalysis
void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) const {
void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
    // Add any new data
    processAndFlushTimeStampSeries();

    if (mHists.empty()) {
        ALOGD("reportPerformance: mHists is empty");
        return;
@@ -348,11 +346,19 @@ void PerformanceAnalysis::alertIfGlitch(const std::vector<int64_t> &samples) {
//------------------------------------------------------------------------------

// writes summary of performance into specified file descriptor
void dump(int fd, int indent, const std::map<int, PerformanceAnalysis>
          &threadPerformanceAnalysis) {
void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
    String8 body;
    const char* const kName = "/data/misc/audioserver/";
    for (auto & thread : threadPerformanceAnalysis) {
        thread.second.reportPerformance(&body);
        for (auto & hash: thread.second) {
            PerformanceAnalysis& curr = hash.second;
            curr.processAndFlushTimeStampSeries();
            // write performance data to console
            curr.reportPerformance(&body);
            // write to file
            writeToFile(curr.mOutlierData, curr.mHists, kName, false,
                        thread.first, hash.first);
        }
    }
    if (!body.isEmpty()) {
        dumpLine(fd, indent, body);
+27 −13
Original line number Diff line number Diff line
@@ -23,12 +23,12 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <sys/prctl.h>
#include <utility>
#include <media/nbaio/NBLog.h>
#include <media/nbaio/PerformanceAnalysis.h>
#include <media/nbaio/ReportPerformance.h>
// #include <utils/CallStack.h> // used to print callstack
#include <utils/Log.h>
#include <utils/String8.h>

@@ -40,34 +40,48 @@ namespace ReportPerformance {
// TODO: format the data efficiently and write different types of data to different files
void writeToFile(const std::deque<std::pair<outlierInterval, timestamp>> &outlierData,
                                    const std::deque<std::pair<timestamp, Histogram>> &hists,
                                    const char * kName,
                                    bool append) {
    ALOGD("writing performance data to file");
                                    const char * kDirectory,
                                    bool append, int author, log_hash_t hash) {
    if (outlierData.empty() || hists.empty()) {
        ALOGW("No data, returning.");
        return;
    }

    std::stringstream outlierName;
    std::stringstream histogramName;

    outlierName << kDirectory << "outliers_" << author << "_" << hash;
    histogramName << kDirectory << "histograms_" << author << "_" << hash;

    std::ofstream ofs;
    ofs.open(kName, append ? std::ios::app : std::ios::trunc);
    ofs.open(outlierName.str().c_str(), append ? std::ios::app : std::ios::trunc);
    if (!ofs.is_open()) {
        ALOGW("couldn't open file %s", kName);
        ALOGW("couldn't open file %s", outlierName.str().c_str());
        return;
    }
    ofs << "Outlier data: interval and timestamp\n";
    for (const auto &outlier : outlierData) {
        ofs << outlier.first << ": " << outlier.second << "\n";
    }
    ofs << "Histogram data\n";
    ofs.close();

    std::ofstream hfs;
    hfs.open(histogramName.str().c_str(), append ? std::ios::app : std::ios::trunc);
    if (!hfs.is_open()) {
        ALOGW("couldn't open file %s", histogramName.str().c_str());
        return;
    }
    hfs << "Histogram data\n";
    for (const auto &hist : hists) {
        ofs << "\ttimestamp\n";
        ofs << hist.first << "\n";
        ofs << "\tbuckets and counts\n";
        hfs << "\ttimestamp\n";
        hfs << hist.first << "\n";
        hfs << "\tbuckets and counts\n";
        for (const auto &bucket : hist.second) {
            ofs << bucket.first << ": " << bucket.second << "\n";
            hfs << bucket.first << ": " << bucket.second << "\n";
        }
        ofs << "\n"; // separate histograms with a newline
        hfs << "\n"; // separate histograms with a newline
    }
    ofs.close();
    hfs.close();
}

} // namespace ReportPerformance
+3 −1
Original line number Diff line number Diff line
@@ -557,7 +557,9 @@ public:
        const std::vector<NamedReader>& mNamedReaders;

        // analyzes, compresses and stores the merged data
        std::map<int, ReportPerformance::PerformanceAnalysis> mThreadPerformanceAnalysis;
        // contains a separate instance for every author (thread), and for every source file
        // location within each author
        ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;

        // handle author entry by looking up the author's name and appending it to the body
        // returns number of bytes read from fmtEntry
+11 −9
Original line number Diff line number Diff line
@@ -29,6 +29,12 @@ namespace android {

namespace ReportPerformance {

class PerformanceAnalysis;

// a map of PerformanceAnalysis instances
// The outer key is for the thread, the inner key for the source file location.
using PerformanceAnalysisMap = std::map<int, std::map<log_hash_t, PerformanceAnalysis>>;

class PerformanceAnalysis {
    // This class stores and analyzes audio processing wakeup timestamps from NBLog
    // FIXME: currently, all performance data is stored in deques. Need to add a mutex.
@@ -38,15 +44,13 @@ public:

    PerformanceAnalysis();

    // Given a series of audio processing wakeup timestamps,
    // compresses and and analyzes the data, and flushes
    // the timestamp series from memory.
    void processAndFlushTimeStampSeries();
    friend void dump(int fd, int indent,
                     PerformanceAnalysisMap &threadPerformanceAnalysis);

    // Given a series of audio processing wakeup timestamps,
    // compresses and and analyzes the data, and flushes
    // the timestamp series from memory.
    void processAndFlushTimeStampSeriesOld();
    void processAndFlushTimeStampSeries();

    // Called when an audio on/off event is read from the buffer,
    // e.g. EVENT_AUDIO_STATE.
@@ -73,7 +77,7 @@ public:
    // input: series of short histograms. Generates a string of analysis of the buffer periods
    // TODO: WIP write more detailed analysis
    // FIXME: move this data visualization to a separate class. Model/view/controller
    void reportPerformance(String8 *body, int maxHeight = 10) const;
    void reportPerformance(String8 *body, int maxHeight = 10);

    // TODO: delete this. temp for testing
    void testFunction();
@@ -134,9 +138,7 @@ private:

};

void dump(int fd, int indent, const std::map<int, PerformanceAnalysis>
          &threadPerformanceAnalysis);

void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
void dumpLine(int fd, int indent, const String8 &body);

} // namespace ReportPerformance
Loading