Merge "logd: add Chattiest LOG_TAG statistics" am: 8c437b95d3
am: a4015dce4c
Change-Id: Ifb927261c2f0ef3b641fdc26a6e30d8d40254ac4
This commit is contained in:
commit
95a5521140
2 changed files with 253 additions and 23 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue