logd: Add TID statistics
Bug: 19608965
Change-Id: Ifbf0b00c48ef12b5970b9f9f217bd1dd8f587f2c
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 164faa9..975265b 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -58,7 +58,7 @@
}
// caller must own and free character string
-static char *tidToName(pid_t tid) {
+char *android::tidToName(pid_t tid) {
char *retval = NULL;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
@@ -108,9 +108,9 @@
static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
char *name = parent->uidToName(mUid);
- char *commName = tidToName(mTid);
+ char *commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
- commName = tidToName(mPid);
+ commName = android::tidToName(mPid);
}
if (!commName) {
commName = parent->pidToName(mPid);
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 75ec59e..55f3d44 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -35,6 +35,7 @@
// Furnished in LogStatistics.cpp. Caller must own and free returned value
char *pidToName(pid_t pid);
+char *tidToName(pid_t tid);
// Furnished in main.cpp. Thread safe.
const char *tagToName(uint32_t tag);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 4511e0b..8fc4e56 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -80,6 +80,7 @@
}
pidTable.add(e->getPid(), e);
+ tidTable.add(e->getTid(), e);
uint32_t tag = e->getTag();
if (tag) {
@@ -100,6 +101,7 @@
}
pidTable.subtract(e->getPid(), e);
+ tidTable.subtract(e->getTid(), e);
uint32_t tag = e->getTag();
if (tag) {
@@ -121,6 +123,7 @@
}
pidTable.drop(e->getPid(), e);
+ tidTable.drop(e->getTid(), e);
}
// caller must own and free character string
@@ -383,6 +386,63 @@
}
}
+ if (enable) {
+ // Tid table
+ bool headerPrinted = false;
+ // sort() returns list of references, unique_ptr makes sure self-delete
+ std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
+ ssize_t index = -1;
+ while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+ const TidEntry *entry = sorted[index];
+ uid_t u = entry->getUid();
+ if ((uid != AID_ROOT) && (u != uid)) {
+ continue;
+ }
+
+ if (!headerPrinted) { // Only print header if we have table to print
+ output.appendFormat("\n\n");
+ android::String8 name("Chattiest TIDs:");
+ android::String8 size("Size");
+ android::String8 pruned("Pruned");
+ format_line(output, name, size, pruned);
+
+ name.setTo(" TID/UID COMM");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ format_line(output, name, size, pruned);
+
+ headerPrinted = true;
+ }
+
+ android::String8 name("");
+ name.appendFormat("%5u/%u", entry->getKey(), u);
+ const char *n = entry->getName();
+ if (n) {
+ name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+ } else {
+ // if we do not have a PID name, lets punt to try UID name?
+ char *un = uidToName(u);
+ if (un) {
+ name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+ free(un);
+ }
+ // We tried, better to not have a name at all, we still
+ // have TID/UID by number to report in any case.
+ }
+
+ android::String8 size("");
+ size.appendFormat("%zu", entry->getSizes());
+
+ android::String8 pruned("");
+ size_t dropped = entry->getDropped();
+ if (dropped) {
+ pruned.appendFormat("%zu", dropped);
+ }
+
+ format_line(output, name, size, pruned);
+ }
+ }
+
if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
// Tag table
bool headerPrinted = false;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index d21a75b..f60f3ed 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -209,6 +209,58 @@
}
};
+struct TidEntry : public EntryBaseDropped {
+ const pid_t tid;
+ uid_t uid;
+ char *name;
+
+ TidEntry(pid_t t):
+ EntryBaseDropped(),
+ tid(t),
+ uid(android::pidToUid(t)),
+ name(android::tidToName(tid)) { }
+ TidEntry(LogBufferElement *e):
+ EntryBaseDropped(e),
+ tid(e->getTid()),
+ uid(e->getUid()),
+ name(android::tidToName(e->getTid())) { }
+ TidEntry(const TidEntry &c):
+ EntryBaseDropped(c),
+ tid(c.tid),
+ uid(c.uid),
+ name(c.name ? strdup(c.name) : NULL) { }
+ ~TidEntry() { free(name); }
+
+ const pid_t&getKey() const { return tid; }
+ const uid_t&getUid() const { return uid; }
+ const char*getName() const { return name; }
+
+ inline void add(pid_t t) {
+ if (name && !strncmp(name, "zygote", 6)) {
+ free(name);
+ name = NULL;
+ }
+ if (!name) {
+ char *n = android::tidToName(t);
+ if (n) {
+ name = n;
+ }
+ }
+ }
+
+ inline void add(LogBufferElement *e) {
+ uid_t u = e->getUid();
+ if (getUid() != u) {
+ uid = u;
+ free(name);
+ name = android::tidToName(e->getTid());
+ } else {
+ add(e->getTid());
+ }
+ EntryBaseDropped::add(e);
+ }
+};
+
struct TagEntry : public EntryBase {
const uint32_t tag;
uid_t uid;
@@ -247,6 +299,10 @@
typedef LogHashtable<pid_t, PidEntry> pidTable_t;
pidTable_t pidTable;
+ // tid to uid list
+ typedef LogHashtable<pid_t, TidEntry> tidTable_t;
+ tidTable_t tidTable;
+
// tag list
typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
tagTable_t tagTable;