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

Commit 813b1b8e authored by Ray Essick's avatar Ray Essick
Browse files

Remove media metrics' unused 'summarizer' concept

Remove the code from media metrics that provided a summarization
capability. It wasn't providing the information we wanted and
consumed more system RAM while being unhelpful.  If we figure out
a better way to do this, we'll re-implement.

Bug: 71874635
Test: manual
parent 0cde7e58
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -6,11 +6,6 @@ include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    main_mediametrics.cpp              \
    MetricsSummarizerCodec.cpp         \
    MetricsSummarizerExtractor.cpp     \
    MetricsSummarizerPlayer.cpp        \
    MetricsSummarizerRecorder.cpp      \
    MetricsSummarizer.cpp              \
    MediaAnalyticsService.cpp

LOCAL_SHARED_LIBRARIES := \
+1 −156
Original line number Diff line number Diff line
@@ -74,26 +74,11 @@

#include "MediaAnalyticsService.h"

#include "MetricsSummarizer.h"
#include "MetricsSummarizerCodec.h"
#include "MetricsSummarizerExtractor.h"
#include "MetricsSummarizerPlayer.h"
#include "MetricsSummarizerRecorder.h"


namespace android {

    using namespace android::base;
    using namespace android::content::pm;



// summarized records
// up to 36 sets, each covering an hour -- so at least 1.5 days
// (will be longer if there are hours without any media action)
static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
static const int kMaxRecordSets = 36;

// individual records kept in memory: age or count
// age: <= 36 hours (1.5 days)
// count: hard limit of # records
@@ -108,57 +93,9 @@ void MediaAnalyticsService::instantiate() {
            String16(kServiceName), new MediaAnalyticsService());
}

// handle sets of summarizers
MediaAnalyticsService::SummarizerSet::SummarizerSet() {
    mSummarizers = new List<MetricsSummarizer *>();
}

MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
    // empty the list
    List<MetricsSummarizer *> *l = mSummarizers;
    while (l->size() > 0) {
        MetricsSummarizer *summarizer = *(l->begin());
        l->erase(l->begin());
        delete summarizer;
    }
}

void MediaAnalyticsService::newSummarizerSet() {
    ALOGD("MediaAnalyticsService::newSummarizerSet");
    MediaAnalyticsService::SummarizerSet *set = new MediaAnalyticsService::SummarizerSet();
    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    set->setStarted(now);

    set->appendSummarizer(new MetricsSummarizerExtractor("extractor"));
    set->appendSummarizer(new MetricsSummarizerCodec("codec"));
    set->appendSummarizer(new MetricsSummarizerPlayer("nuplayer"));
    set->appendSummarizer(new MetricsSummarizerRecorder("recorder"));

    // ALWAYS at the end, since it catches everything
    set->appendSummarizer(new MetricsSummarizer(NULL));

    // inject this set at the BACK of the list.
    mSummarizerSets->push_back(set);
    mCurrentSet = set;

    // limit the # that we have
    if (mMaxRecordSets > 0) {
        List<SummarizerSet *> *l = mSummarizerSets;
        while (l->size() > (size_t) mMaxRecordSets) {
            ALOGD("Deleting oldest record set....");
            MediaAnalyticsService::SummarizerSet *oset = *(l->begin());
            l->erase(l->begin());
            delete oset;
            mSetsDiscarded++;
        }
    }
}

MediaAnalyticsService::MediaAnalyticsService()
        : mMaxRecords(kMaxRecords),
          mMaxRecordAgeNs(kMaxRecordAgeNs),
          mMaxRecordSets(kMaxRecordSets),
          mNewSetInterval(kNewSetIntervalNs),
          mDumpProto(MediaAnalyticsItem::PROTO_V1),
          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {

@@ -167,9 +104,6 @@ MediaAnalyticsService::MediaAnalyticsService()
    mOpen = new List<MediaAnalyticsItem *>();
    mFinalized = new List<MediaAnalyticsItem *>();

    mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
    newSummarizerSet();

    mItemsSubmitted = 0;
    mItemsFinalized = 0;
    mItemsDiscarded = 0;
@@ -204,8 +138,6 @@ MediaAnalyticsService::~MediaAnalyticsService() {
    }
    delete mFinalized;
    mFinalized = NULL;

    // XXX: clean out the summaries
}


@@ -315,13 +247,11 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
                oitem = NULL;
            } else {
                oitem->setFinalized(true);
                summarize(oitem);
                saveItem(mFinalized, oitem, 0);
            }
            // new record could itself be marked finalized...
            id = item->getSessionID();
            if (finalizing) {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            } else {
@@ -332,7 +262,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
            oitem->merge(item);
            id = oitem->getSessionID();
            if (finalizing) {
                summarize(oitem);
                saveItem(mFinalized, oitem, 0);
                mItemsFinalized++;
            }
@@ -350,7 +279,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
                delete item;
                item = NULL;
            } else {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            }
@@ -379,8 +307,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
    }

    // crack any parameters
    String16 summaryOption("-summary");
    bool summary = false;
    String16 protoOption("-proto");
    int chosenProto = mDumpProtoDefault;
    String16 clearOption("-clear");
@@ -396,8 +322,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
        String8 myarg(args[i]);
        if (args[i] == clearOption) {
            clear = true;
        } else if (args[i] == summaryOption) {
            summary = true;
        } else if (args[i] == protoOption) {
            i++;
            if (i < n) {
@@ -444,7 +368,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
            result.append("Recognized parameters:\n");
            result.append("-help        this help message\n");
            result.append("-proto #     dump using protocol #");
            result.append("-summary     show summary info\n");
            result.append("-clear       clears out saved records\n");
            result.append("-only X      process records for component X\n");
            result.append("-since X     include records since X\n");
@@ -464,12 +387,7 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)

    dumpHeaders(result, ts_since);

    // want exactly 1, to avoid confusing folks that parse the output
    if (summary) {
        dumpSummaries(result, ts_since, only.c_str());
    } else {
    dumpRecent(result, ts_since, only.c_str());
    }


    if (clear) {
@@ -526,40 +444,6 @@ void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
    }
}

// dump summary info
void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
    const size_t SIZE = 512;
    char buffer[SIZE];
    int slot = 0;

    snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
    result.append(buffer);

    if (only != NULL && *only == '\0') {
        only = NULL;
    }

    // have each of the distillers dump records
    if (mSummarizerSets != NULL) {
        List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
        for (; itSet != mSummarizerSets->end(); itSet++) {
            nsecs_t when = (*itSet)->getStarted();
            if (when < ts_since) {
                continue;
            }
            List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
            List<MetricsSummarizer *>::iterator it = list->begin();
            for (; it != list->end(); it++) {
                if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
                    ALOGV("Told to omit '%s'", (*it)->getKey());
                }
                std::string distilled = (*it)->dumpSummary(slot, only);
                result.append(distilled.c_str());
            }
        }
    }
}

// the recent, detailed queues
void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
    const size_t SIZE = 512;
@@ -785,45 +669,6 @@ bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
    return false;
}

// insert into the appropriate summarizer.
// we make our own copy to save/summarize
void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {

    ALOGV("MediaAnalyticsService::summarize()");

    if (item == NULL) {
        return;
    }

    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    if (mCurrentSet == NULL
        || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
        newSummarizerSet();
    }

    if (mCurrentSet == NULL) {
        return;
    }

    List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
    List<MetricsSummarizer *>::iterator it = summarizers->begin();
    for (; it != summarizers->end(); it++) {
        if ((*it)->isMine(*item)) {
            break;
        }
    }
    if (it == summarizers->end()) {
        ALOGD("no handler for type %s", item->getKey().c_str());
        return;               // no handler
    }

    // invoke the summarizer. summarizer will make whatever copies
    // it wants; the caller retains ownership of item.

    (*it)->handleRecord(item);

}

// how long we hold package info before we re-fetch it
#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs

+0 −33
Original line number Diff line number Diff line
@@ -28,9 +28,6 @@

#include <media/IMediaAnalyticsService.h>

#include "MetricsSummarizer.h"


namespace android {

class MediaAnalyticsService : public BnMediaAnalyticsService
@@ -89,36 +86,6 @@ class MediaAnalyticsService : public BnMediaAnalyticsService
    MediaAnalyticsItem *findItem(List<MediaAnalyticsItem *> *,
                                     MediaAnalyticsItem *, bool removeit);

    // summarizers
    void summarize(MediaAnalyticsItem *item);
    class SummarizerSet {
        nsecs_t mStarted;
        List<MetricsSummarizer *> *mSummarizers;

      public:
        void appendSummarizer(MetricsSummarizer *s) {
            if (s) {
                mSummarizers->push_back(s);
            }
        };
        nsecs_t getStarted() { return mStarted;}
        void setStarted(nsecs_t started) {mStarted = started;}
        List<MetricsSummarizer *> *getSummarizers() { return mSummarizers;}

        SummarizerSet();
        ~SummarizerSet();
    };
    void newSummarizerSet();
    List<SummarizerSet *> *mSummarizerSets;
    SummarizerSet *mCurrentSet;
    List<MetricsSummarizer *> *getFirstSet() {
        List<SummarizerSet *>::iterator first = mSummarizerSets->begin();
        if (first != mSummarizerSets->end()) {
            return (*first)->getSummarizers();
        }
        return NULL;
    }

    void saveItem(MediaAnalyticsItem);
    void saveItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *, int);
    void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
+0 −348
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "MetricsSummarizer"
#include <utils/Log.h>

#include <stdlib.h>
#include <stdint.h>
#include <string>
#include <inttypes.h>

#include <utils/threads.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/List.h>

#include <media/IMediaAnalyticsService.h>

#include "MetricsSummarizer.h"


namespace android {

#define DEBUG_SORT      0
#define DEBUG_QUEUE     0


MetricsSummarizer::MetricsSummarizer(const char *key)
    : mIgnorables(NULL)
{
    ALOGV("MetricsSummarizer::MetricsSummarizer");

    if (key == NULL) {
        mKey = key;
    } else {
        mKey = strdup(key);
    }

    mSummaries = new List<MediaAnalyticsItem *>();
}

MetricsSummarizer::~MetricsSummarizer()
{
    ALOGV("MetricsSummarizer::~MetricsSummarizer");
    if (mKey) {
        free((void *)mKey);
        mKey = NULL;
    }

    // clear the list of items we have saved
    while (mSummaries->size() > 0) {
        MediaAnalyticsItem * oitem = *(mSummaries->begin());
        if (DEBUG_QUEUE) {
            ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
                oitem->getKey().c_str(), oitem->getSessionID(),
                oitem->getTimestamp());
        }
        mSummaries->erase(mSummaries->begin());
        delete oitem;
    }
}

// so we know what summarizer we were using
const char *MetricsSummarizer::getKey() {
    const char *value = mKey;
    if (value == NULL) {
        value = "unknown";
    }
    return value;
}

// should the record be given to this summarizer
bool MetricsSummarizer::isMine(MediaAnalyticsItem &item)
{
    if (mKey == NULL)
        return true;
    std::string itemKey = item.getKey();
    if (strcmp(mKey, itemKey.c_str()) != 0) {
        return false;
    }
    return true;
}

std::string MetricsSummarizer::dumpSummary(int &slot)
{
    return dumpSummary(slot, NULL);
}

std::string MetricsSummarizer::dumpSummary(int &slot, const char *only)
{
    std::string value;

    List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
    if (it != mSummaries->end()) {
        char buf[16];   // enough for "#####: "
        for (; it != mSummaries->end(); it++) {
            if (only != NULL && strcmp(only, (*it)->getKey().c_str()) != 0) {
                continue;
            }
            std::string entry = (*it)->toString();
            snprintf(buf, sizeof(buf), "%5d: ", slot);
            value.append(buf);
            value.append(entry.c_str());
            value.append("\n");
            slot++;
        }
    }
    return value;
}

void MetricsSummarizer::setIgnorables(const char **ignorables) {
    mIgnorables = ignorables;
}

const char **MetricsSummarizer::getIgnorables() {
    return mIgnorables;
}

void MetricsSummarizer::handleRecord(MediaAnalyticsItem *item) {

    ALOGV("MetricsSummarizer::handleRecord() for %s",
                item == NULL ? "<nothing>" : item->toString().c_str());

    if (item == NULL) {
        return;
    }

    List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
    for (; it != mSummaries->end(); it++) {
        bool good = sameAttributes((*it), item, getIgnorables());
        ALOGV("Match against %s says %d", (*it)->toString().c_str(), good);
        if (good)
            break;
    }
    if (it == mSummaries->end()) {
            ALOGV("save new record");
            MediaAnalyticsItem *nitem = item->dup();
            if (nitem == NULL) {
                ALOGE("unable to save MediaMetrics record");
            }
            sortProps(nitem);
            nitem->setInt32("aggregated",1);
            mergeRecord(*nitem, *item);
            mSummaries->push_back(nitem);
    } else {
            ALOGV("increment existing record");
            (*it)->addInt32("aggregated",1);
            mergeRecord(*(*it), *item);
    }
}

void MetricsSummarizer::mergeRecord(MediaAnalyticsItem &/*have*/, MediaAnalyticsItem &/*item*/) {
    // default is no further massaging.
    ALOGV("MetricsSummarizer::mergeRecord() [default]");
    return;
}

// keep some stats for things: sums, counts, standard deviation
// the integer version -- all of these pieces are in 64 bits
void MetricsSummarizer::minMaxVar64(MediaAnalyticsItem &summation, const char *key, int64_t value) {
    if (key == NULL)
        return;
    int len = strlen(key) + 32;
    char *tmpKey = (char *)malloc(len);

    if (tmpKey == NULL) {
        return;
    }

    // N - count of samples
    snprintf(tmpKey, len, "%s.n", key);
    summation.addInt64(tmpKey, 1);

    // zero - count of samples that are zero
    if (value == 0) {
        snprintf(tmpKey, len, "%s.zero", key);
        int64_t zero = 0;
        (void) summation.getInt64(tmpKey,&zero);
        zero++;
        summation.setInt64(tmpKey, zero);
    }

    // min
    snprintf(tmpKey, len, "%s.min", key);
    int64_t min = value;
    if (summation.getInt64(tmpKey,&min)) {
        if (min > value) {
            summation.setInt64(tmpKey, value);
        }
    } else {
        summation.setInt64(tmpKey, value);
    }

    // max
    snprintf(tmpKey, len, "%s.max", key);
    int64_t max = value;
    if (summation.getInt64(tmpKey,&max)) {
        if (max < value) {
            summation.setInt64(tmpKey, value);
        }
    } else {
        summation.setInt64(tmpKey, value);
    }

    // components for mean, stddev;
    // stddev = sqrt(1/4*(sumx2 - (2*sumx*sumx/n) + ((sumx/n)^2)))
    // sum x
    snprintf(tmpKey, len, "%s.sumX", key);
    summation.addInt64(tmpKey, value);
    // sum x^2
    snprintf(tmpKey, len, "%s.sumX2", key);
    summation.addInt64(tmpKey, value*value);


    // last thing we do -- remove the base key from the summation
    // record so we won't get confused about it having both individual
    // and summary information in there.
    summation.removeProp(key);

    free(tmpKey);
}


//
// Comparators
//

// testing that all of 'single' is in 'summ'
// and that the values match.
// 'summ' may have extra fields.
// 'ignorable' is a set of things that we don't worry about matching up
// (usually time- or count-based values we'll sum elsewhere)
bool MetricsSummarizer::sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {

    if (single == NULL || summ == NULL) {
        return false;
    }
    ALOGV("MetricsSummarizer::sameAttributes(): summ %s", summ->toString().c_str());
    ALOGV("MetricsSummarizer::sameAttributes(): single %s", single->toString().c_str());

    // keep different sources/users separate
    if (single->mUid != summ->mUid) {
        return false;
    }

    // this can be made better.
    for(size_t i=0;i<single->mPropCount;i++) {
        MediaAnalyticsItem::Prop *prop1 = &(single->mProps[i]);
        const char *attrName = prop1->mName;

        // is it something we should ignore
        if (ignorable != NULL) {
            const char **ig = ignorable;
            for (;*ig; ig++) {
                if (strcmp(*ig, attrName) == 0) {
                    break;
                }
            }
            if (*ig) {
                ALOGV("we don't mind that it has attr '%s'", attrName);
                continue;
            }
        }

        MediaAnalyticsItem::Prop *prop2 = summ->findProp(attrName);
        if (prop2 == NULL) {
            ALOGV("summ doesn't have this attr");
            return false;
        }
        if (prop1->mType != prop2->mType) {
            ALOGV("mismatched attr types");
            return false;
        }
        switch (prop1->mType) {
            case MediaAnalyticsItem::kTypeInt32:
                if (prop1->u.int32Value != prop2->u.int32Value) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeInt64:
                if (prop1->u.int64Value != prop2->u.int64Value) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeDouble:
                // XXX: watch out for floating point comparisons!
                if (prop1->u.doubleValue != prop2->u.doubleValue) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeCString:
                if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeRate:
                if (prop1->u.rate.count != prop2->u.rate.count) {
                    ALOGV("mismatch values");
                    return false;
                }
                if (prop1->u.rate.duration != prop2->u.rate.duration) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            default:
                ALOGV("mismatch values in default type");
                return false;
        }
    }

    return true;
}


int MetricsSummarizer::PropSorter(const void *a, const void *b) {
    MediaAnalyticsItem::Prop *ai = (MediaAnalyticsItem::Prop *)a;
    MediaAnalyticsItem::Prop *bi = (MediaAnalyticsItem::Prop *)b;
    return strcmp(ai->mName, bi->mName);
}

// we sort in the summaries so that it looks pretty in the dumpsys
void MetricsSummarizer::sortProps(MediaAnalyticsItem *item) {
    if (item->mPropCount != 0) {
        qsort(item->mProps, item->mPropCount,
              sizeof(MediaAnalyticsItem::Prop), MetricsSummarizer::PropSorter);
    }
}

} // namespace android
+0 −81
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef ANDROID_METRICSSUMMARIZER_H
#define ANDROID_METRICSSUMMARIZER_H

#include <string>
#include <utils/threads.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>

#include <media/IMediaAnalyticsService.h>


namespace android {

class MetricsSummarizer
{

 public:

    MetricsSummarizer(const char *key);
    virtual ~MetricsSummarizer();

    // show the key
    const char * getKey();

    // should the record be given to this summarizer
    bool isMine(MediaAnalyticsItem &item);

    // hand the record to this summarizer
    void handleRecord(MediaAnalyticsItem *item);

    virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);

    // dump the summarized records (for dumpsys)
    std::string dumpSummary(int &slot);
    std::string dumpSummary(int &slot, const char *only);

    void setIgnorables(const char **);
    const char **getIgnorables();

 protected:

    // various comparators
    // "do these records have same attributes and values in those attrs"
    bool sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);

    void minMaxVar64(MediaAnalyticsItem &summ, const char *key, int64_t value);

    static int PropSorter(const void *a, const void *b);
    void sortProps(MediaAnalyticsItem *item);

 private:
    const char *mKey;
    const char **mIgnorables;
    List<MediaAnalyticsItem *> *mSummaries;


};

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

}; // namespace android

#endif // ANDROID_METRICSSUMMARIZER_H
Loading