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

Commit 8c437b95 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "logd: add Chattiest LOG_TAG statistics"

parents 8df35dcb f99a7d60
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -152,6 +152,10 @@ void LogStatistics::add(LogBufferElement* element) {
            tagTable.add(tag, element);
        }
    }

    if (!element->getDropped()) {
        tagNameTable.add(TagNameKey(element), element);
    }
}

void LogStatistics::subtract(LogBufferElement* element) {
@@ -191,6 +195,10 @@ void LogStatistics::subtract(LogBufferElement* element) {
            tagTable.subtract(tag, element);
        }
    }

    if (!element->getDropped()) {
        tagNameTable.subtract(TagNameKey(element), element);
    }
}

// Atomically set an entry to drop
@@ -225,6 +233,8 @@ void LogStatistics::drop(LogBufferElement* element) {
            tagTable.drop(tag, element);
        }
    }

    tagNameTable.subtract(TagNameKey(element), element);
}

// caller must own and free character string
@@ -505,6 +515,62 @@ std::string TagEntry::format(const LogStatistics& /* stat */,
    return formatLine(name, size, pruned);
}

std::string TagNameEntry::formatHeader(const std::string& name,
                                       log_id_t /* id */) const {
    return formatLine(name, std::string("Size"), std::string("")) +
           formatLine(std::string("  TID/PID/UID   LOG_TAG NAME"),
                      std::string("BYTES"), std::string(""));
}

std::string TagNameEntry::format(const LogStatistics& /* stat */,
                                 log_id_t /* id */) const {
    std::string name;
    pid_t tid = getTid();
    pid_t pid = getPid();
    std::string pidstr;
    if (pid != (pid_t)-1) {
        pidstr = android::base::StringPrintf("%u", pid);
        if ((tid != (pid_t)-1) && (tid != pid)) pidstr = "/" + pidstr;
    }
    int len = 9 - pidstr.length();
    if (len < 0) len = 0;
    if ((tid == (pid_t)-1) || (tid == pid)) {
        name = android::base::StringPrintf("%*s", len, "");
    } else {
        name = android::base::StringPrintf("%*u", len, tid);
    }
    name += pidstr;
    uid_t uid = getUid();
    if (uid != (uid_t)-1) {
        name += android::base::StringPrintf("/%u", uid);
    }

    std::string size = android::base::StringPrintf("%zu", getSizes());

    const char* nameTmp = getName();
    if (nameTmp) {
        size_t lenSpace = std::max(16 - name.length(), (size_t)1);
        size_t len = EntryBaseConstants::total_len -
                     EntryBaseConstants::pruned_len - size.length() -
                     name.length() - lenSpace - 2;
        size_t lenNameTmp = strlen(nameTmp);
        while ((len < lenNameTmp) && (lenSpace > 1)) {
            ++len;
            --lenSpace;
        }
        name += android::base::StringPrintf("%*s", (int)lenSpace, "");
        if (len < lenNameTmp) {
            name += "...";
            nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
        }
        name += nameTmp;
    }

    std::string pruned = "";

    return formatLine(name, size, pruned);
}

static std::string formatMsec(uint64_t val) {
    static const unsigned subsecDigits = 3;
    static const uint64_t sec = MS_PER_SEC;
@@ -740,6 +806,13 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
            securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
    }

    if (enable) {
        name = "Chattiest TAGs";
        if (pid) name += android::base::StringPrintf(" for PID %d", pid);
        name += ":";
        output += tagNameTable.format(*this, uid, pid, name);
    }

    return output;
}

+180 −23
Original line number Diff line number Diff line
@@ -18,10 +18,14 @@
#define _LOGD_LOG_STATISTICS_H__

#include <ctype.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include <algorithm>  // std::max
#include <experimental/string_view>
#include <memory>
#include <string>  // std::string
#include <unordered_map>
@@ -30,6 +34,7 @@
#include <android/log.h>
#include <log/log_time.h>
#include <private/android_filesystem_config.h>
#include <utils/FastStrcmp.h>

#include "LogBufferElement.h"
#include "LogUtils.h"
@@ -77,7 +82,7 @@ class LogHashtable {
    std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
                                           size_t len) const {
        if (!len) {
            std::unique_ptr<const TEntry* []> sorted(NULL);
            std::unique_ptr<const TEntry* []> sorted(nullptr);
            return sorted;
        }

@@ -112,7 +117,7 @@ class LogHashtable {
        return sorted;
    }

    inline iterator add(TKey key, LogBufferElement* element) {
    inline iterator add(const TKey& key, const LogBufferElement* element) {
        iterator it = map.find(key);
        if (it == map.end()) {
            it = map.insert(std::make_pair(key, TEntry(element))).first;
@@ -132,14 +137,21 @@ class LogHashtable {
        return it;
    }

    void subtract(TKey key, LogBufferElement* element) {
    void subtract(TKey&& key, const LogBufferElement* element) {
        iterator it = map.find(std::move(key));
        if ((it != map.end()) && it->second.subtract(element)) {
            map.erase(it);
        }
    }

    void subtract(const TKey& key, const LogBufferElement* element) {
        iterator it = map.find(key);
        if ((it != map.end()) && it->second.subtract(element)) {
            map.erase(it);
        }
    }

    inline void drop(TKey key, LogBufferElement* element) {
    inline void drop(TKey key, const LogBufferElement* element) {
        iterator it = map.find(key);
        if (it != map.end()) {
            it->second.drop(element);
@@ -199,17 +211,18 @@ struct EntryBase {

    EntryBase() : size(0) {
    }
    explicit EntryBase(LogBufferElement* element) : size(element->getMsgLen()) {
    explicit EntryBase(const LogBufferElement* element)
        : size(element->getMsgLen()) {
    }

    size_t getSizes() const {
        return size;
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        size += element->getMsgLen();
    }
    inline bool subtract(LogBufferElement* element) {
    inline bool subtract(const LogBufferElement* element) {
        size -= element->getMsgLen();
        return !size;
    }
@@ -240,7 +253,7 @@ struct EntryBaseDropped : public EntryBase {

    EntryBaseDropped() : dropped(0) {
    }
    explicit EntryBaseDropped(LogBufferElement* element)
    explicit EntryBaseDropped(const LogBufferElement* element)
        : EntryBase(element), dropped(element->getDropped()) {
    }

@@ -248,15 +261,15 @@ struct EntryBaseDropped : public EntryBase {
        return dropped;
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        dropped += element->getDropped();
        EntryBase::add(element);
    }
    inline bool subtract(LogBufferElement* element) {
    inline bool subtract(const LogBufferElement* element) {
        dropped -= element->getDropped();
        return EntryBase::subtract(element) && !dropped;
    }
    inline void drop(LogBufferElement* element) {
    inline void drop(const LogBufferElement* element) {
        dropped += 1;
        EntryBase::subtract(element);
    }
@@ -266,7 +279,7 @@ struct UidEntry : public EntryBaseDropped {
    const uid_t uid;
    pid_t pid;

    explicit UidEntry(LogBufferElement* element)
    explicit UidEntry(const LogBufferElement* element)
        : EntryBaseDropped(element),
          uid(element->getUid()),
          pid(element->getPid()) {
@@ -282,7 +295,7 @@ struct UidEntry : public EntryBaseDropped {
        return pid;
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        if (pid != element->getPid()) {
            pid = -1;
        }
@@ -308,7 +321,7 @@ struct PidEntry : public EntryBaseDropped {
          uid(android::pidToUid(pid)),
          name(android::pidToName(pid)) {
    }
    explicit PidEntry(LogBufferElement* element)
    explicit PidEntry(const LogBufferElement* element)
        : EntryBaseDropped(element),
          pid(element->getPid()),
          uid(element->getUid()),
@@ -318,7 +331,7 @@ struct PidEntry : public EntryBaseDropped {
        : EntryBaseDropped(element),
          pid(element.pid),
          uid(element.uid),
          name(element.name ? strdup(element.name) : NULL) {
          name(element.name ? strdup(element.name) : nullptr) {
    }
    ~PidEntry() {
        free(name);
@@ -340,14 +353,14 @@ struct PidEntry : public EntryBaseDropped {
    inline void add(pid_t newPid) {
        if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
            free(name);
            name = NULL;
            name = nullptr;
        }
        if (!name) {
            name = android::pidToName(newPid);
        }
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        uid_t incomingUid = element->getUid();
        if (getUid() != incomingUid) {
            uid = incomingUid;
@@ -376,7 +389,7 @@ struct TidEntry : public EntryBaseDropped {
          uid(android::pidToUid(tid)),
          name(android::tidToName(tid)) {
    }
    explicit TidEntry(LogBufferElement* element)
    explicit TidEntry(const LogBufferElement* element)
        : EntryBaseDropped(element),
          tid(element->getTid()),
          pid(element->getPid()),
@@ -388,7 +401,7 @@ struct TidEntry : public EntryBaseDropped {
          tid(element.tid),
          pid(element.pid),
          uid(element.uid),
          name(element.name ? strdup(element.name) : NULL) {
          name(element.name ? strdup(element.name) : nullptr) {
    }
    ~TidEntry() {
        free(name);
@@ -413,14 +426,14 @@ struct TidEntry : public EntryBaseDropped {
    inline void add(pid_t incomingTid) {
        if (name && !fastcmp<strncmp>(name, "zygote", 6)) {
            free(name);
            name = NULL;
            name = nullptr;
        }
        if (!name) {
            name = android::tidToName(incomingTid);
        }
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        uid_t incomingUid = element->getUid();
        pid_t incomingPid = element->getPid();
        if ((getUid() != incomingUid) || (getPid() != incomingPid)) {
@@ -443,7 +456,7 @@ struct TagEntry : public EntryBaseDropped {
    pid_t pid;
    uid_t uid;

    explicit TagEntry(LogBufferElement* element)
    explicit TagEntry(const LogBufferElement* element)
        : EntryBaseDropped(element),
          tag(element->getTag()),
          pid(element->getPid()),
@@ -463,7 +476,7 @@ struct TagEntry : public EntryBaseDropped {
        return android::tagToName(tag);
    }

    inline void add(LogBufferElement* element) {
    inline void add(const LogBufferElement* element) {
        if (uid != element->getUid()) {
            uid = -1;
        }
@@ -477,6 +490,144 @@ struct TagEntry : public EntryBaseDropped {
    std::string format(const LogStatistics& stat, log_id_t id) const;
};

struct TagNameKey {
    std::string* alloc;
    std::experimental::string_view name;  // Saves space if const char*

    explicit TagNameKey(const LogBufferElement* element)
        : alloc(nullptr), name("", strlen("")) {
        if (element->isBinary()) {
            uint32_t tag = element->getTag();
            if (tag) {
                const char* cp = android::tagToName(tag);
                if (cp) {
                    name = std::experimental::string_view(cp, strlen(cp));
                    return;
                }
            }
            alloc = new std::string(
                android::base::StringPrintf("[%" PRIu32 "]", tag));
            if (!alloc) return;
            name = std::experimental::string_view(alloc->c_str(), alloc->size());
            return;
        }
        const char* msg = element->getMsg();
        if (!msg) {
            name = std::experimental::string_view("chatty", strlen("chatty"));
            return;
        }
        ++msg;
        unsigned short len = element->getMsgLen();
        len = (len <= 1) ? 0 : strnlen(msg, len - 1);
        if (!len) {
            name = std::experimental::string_view("<NULL>", strlen("<NULL>"));
            return;
        }
        alloc = new std::string(msg, len);
        if (!alloc) return;
        name = std::experimental::string_view(alloc->c_str(), alloc->size());
    }

    explicit TagNameKey(TagNameKey&& rval)
        : alloc(rval.alloc), name(rval.name.data(), rval.name.length()) {
        rval.alloc = nullptr;
    }

    explicit TagNameKey(const TagNameKey& rval)
        : alloc(rval.alloc ? new std::string(*rval.alloc) : nullptr),
          name(alloc ? alloc->data() : rval.name.data(), rval.name.length()) {
    }

    ~TagNameKey() {
        if (alloc) delete alloc;
    }

    operator const std::experimental::string_view() const {
        return name;
    }

    const char* data() const {
        return name.data();
    }
    size_t length() const {
        return name.length();
    }

    bool operator==(const TagNameKey& rval) const {
        if (length() != rval.length()) return false;
        if (length() == 0) return true;
        return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
    }
    bool operator!=(const TagNameKey& rval) const {
        return !(*this == rval);
    }

    size_t getAllocLength() const {
        return alloc ? alloc->length() + 1 + sizeof(std::string) : 0;
    }
};

// Hash for TagNameKey
template <>
struct std::hash<TagNameKey>
    : public std::unary_function<const TagNameKey&, size_t> {
    size_t operator()(const TagNameKey& __t) const noexcept {
        if (!__t.length()) return 0;
        return std::hash<std::experimental::string_view>()(
            std::experimental::string_view(__t));
    }
};

struct TagNameEntry : public EntryBase {
    pid_t tid;
    pid_t pid;
    uid_t uid;
    TagNameKey name;

    explicit TagNameEntry(const LogBufferElement* element)
        : EntryBase(element),
          tid(element->getTid()),
          pid(element->getPid()),
          uid(element->getUid()),
          name(element) {
    }

    const TagNameKey& getKey() const {
        return name;
    }
    const pid_t& getTid() const {
        return tid;
    }
    const pid_t& getPid() const {
        return pid;
    }
    const uid_t& getUid() const {
        return uid;
    }
    const char* getName() const {
        return name.data();
    }
    size_t getNameAllocLength() const {
        return name.getAllocLength();
    }

    inline void add(const LogBufferElement* element) {
        if (uid != element->getUid()) {
            uid = -1;
        }
        if (pid != element->getPid()) {
            pid = -1;
        }
        if (tid != element->getTid()) {
            tid = -1;
        }
        EntryBase::add(element);
    }

    std::string formatHeader(const std::string& name, log_id_t id) const;
    std::string format(const LogStatistics& stat, log_id_t id) const;
};

template <typename TEntry>
class LogFindWorst {
    std::unique_ptr<const TEntry* []> sorted;
@@ -550,9 +701,14 @@ class LogStatistics {
    // security tag list
    tagTable_t securityTagTable;

    // global tag list
    typedef LogHashtable<TagNameKey, TagNameEntry> tagNameTable_t;
    tagNameTable_t tagNameTable;

    size_t sizeOf() const {
        size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
                      tagTable.sizeOf() + securityTagTable.sizeOf() +
                      tagNameTable.sizeOf() +
                      (pidTable.size() * sizeof(pidTable_t::iterator)) +
                      (tagTable.size() * sizeof(tagTable_t::iterator));
        for (auto it : pidTable) {
@@ -563,6 +719,7 @@ class LogStatistics {
            const char* name = it.second.getName();
            if (name) size += strlen(name) + 1;
        }
        for (auto it : tagNameTable) size += it.second.getNameAllocLength();
        log_id_for_each(id) {
            size += uidTable[id].sizeOf();
            size += uidTable[id].size() * sizeof(uidTable_t::iterator);