diff options
author | Mark Salyzyn <salyzyn@google.com> | 2015-03-10 13:51:35 -0700 |
---|---|---|
committer | Mark Salyzyn <salyzyn@google.com> | 2015-03-20 12:31:23 -0700 |
commit | 97c1c2beee2cbd8c67c1cd507367e5b084d853c8 (patch) | |
tree | 11842d8e150816d839e355582671dad82278ade5 /logd | |
parent | ca87790cdccdb0ee17fb4069e6d4ed1e7b4e2ee0 (diff) | |
download | system_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.zip system_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.tar.gz system_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.tar.bz2 |
logd: optimize statistics
- Go back to basic requirements
- Simplify
- use hash tables to minimize memory impact
Bug: 19608965
Change-Id: If7becb34354d6415e5c387ecea7d4109a15259c8
Diffstat (limited to 'logd')
-rw-r--r-- | logd/LogBuffer.cpp | 169 | ||||
-rw-r--r-- | logd/LogBuffer.h | 2 | ||||
-rw-r--r-- | logd/LogBufferElement.h | 3 | ||||
-rw-r--r-- | logd/LogStatistics.cpp | 864 | ||||
-rw-r--r-- | logd/LogStatistics.h | 165 | ||||
-rw-r--r-- | logd/LogWhiteBlackList.h | 2 |
6 files changed, 281 insertions, 924 deletions
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 2693583..d11b129 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -27,8 +27,6 @@ #include "LogBuffer.h" #include "LogReader.h" -#include "LogStatistics.h" -#include "LogWhiteBlackList.h" // Default #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here? @@ -193,7 +191,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, LogTimeEntry::unlock(); } - stats.add(len, log_id, uid, pid); + stats.add(elem); maybePrune(log_id); pthread_mutex_unlock(&mLogElementsLock); } @@ -216,6 +214,16 @@ void LogBuffer::maybePrune(log_id_t id) { } } +LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) { + LogBufferElement *e = *it; + + it = mLogElements.erase(it); + stats.subtract(e); + delete e; + + return it; +} + // prune "pruneRows" of type "id" from the buffer. // // mLogElementsLock must be held when this function is called. @@ -250,12 +258,8 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { continue; } - uid_t uid = e->getUid(); - - if (uid == caller_uid) { - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, uid, e->getPid()); - delete e; + if (e->getUid() == caller_uid) { + it = erase(it); pruneRows--; if (pruneRows == 0) { break; @@ -269,6 +273,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } // prune by worst offender by uid + bool hasBlacklist = mPrune.naughty(); while (pruneRows > 0) { // recalculate the worst offender on every batched pass uid_t worst = (uid_t) -1; @@ -276,19 +281,23 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { size_t second_worst_sizes = 0; if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) { - LidStatistics &l = stats.id(id); - l.sort(); - UidStatisticsCollection::iterator iu = l.begin(); - if (iu != l.end()) { - UidStatistics *u = *iu; - worst = u->getUid(); - worst_sizes = u->sizes(); - if (++iu != l.end()) { - second_worst_sizes = (*iu)->sizes(); + const UidEntry **sorted = stats.sort(2, id); + + if (sorted) { + if (sorted[0] && sorted[1]) { + worst = sorted[0]->getKey(); + worst_sizes = sorted[0]->getSizes(); + second_worst_sizes = sorted[1]->getSizes(); } + delete [] sorted; } } + // skip if we have neither worst nor naughty filters + if ((worst == (uid_t) -1) && !hasBlacklist) { + break; + } + bool kick = false; for(it = mLogElements.begin(); it != mLogElements.end();) { LogBufferElement *e = *it; @@ -304,24 +313,28 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { uid_t uid = e->getUid(); - if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed - it = mLogElements.erase(it); - unsigned short len = e->getMsgLen(); - stats.subtract(len, id, uid, e->getPid()); - delete e; - pruneRows--; - if (uid == worst) { - kick = true; - if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { - break; - } - worst_sizes -= len; - } else if (pruneRows == 0) { - break; - } - } else { + // !Worst and !BlackListed? + if ((uid != worst) && (!hasBlacklist || !mPrune.naughty(e))) { ++it; + continue; + } + + unsigned short len = e->getMsgLen(); + it = erase(it); + pruneRows--; + if (pruneRows == 0) { + break; + } + + if (uid != worst) { + continue; + } + + kick = true; + if (worst_sizes < second_worst_sizes) { + break; } + worst_sizes -= len; } if (!kick || !mPrune.worstUidEnabled()) { @@ -330,58 +343,63 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } bool whitelist = false; + bool hasWhitelist = mPrune.nice(); it = mLogElements.begin(); while((pruneRows > 0) && (it != mLogElements.end())) { LogBufferElement *e = *it; - if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getSequence())) { - if (!whitelist) { - if (stats.sizes(id) > (2 * log_buffer_size(id))) { - // kick a misbehaving log reader client off the island - oldest->release_Locked(); - } else { - oldest->triggerSkip_Locked(id, pruneRows); - } - } + + if (e->getLogId() != id) { + it++; + continue; + } + + if (oldest && (oldest->mStart <= e->getSequence())) { + if (whitelist) { break; } - if (mPrune.nice(e)) { // WhiteListed - whitelist = true; - it++; - continue; + if (stats.sizes(id) > (2 * log_buffer_size(id))) { + // kick a misbehaving log reader client off the island + oldest->release_Locked(); + } else { + oldest->triggerSkip_Locked(id, pruneRows); } + break; + } - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid()); - delete e; - pruneRows--; - } else { + if (hasWhitelist && mPrune.nice(e)) { // WhiteListed + whitelist = true; it++; + continue; } + + it = erase(it); + pruneRows--; } + // Do not save the whitelist if we are reader range limited if (whitelist && (pruneRows > 0)) { it = mLogElements.begin(); while((it != mLogElements.end()) && (pruneRows > 0)) { LogBufferElement *e = *it; - if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getSequence())) { - if (stats.sizes(id) > (2 * log_buffer_size(id))) { - // kick a misbehaving log reader client off the island - oldest->release_Locked(); - } else { - oldest->triggerSkip_Locked(id, pruneRows); - } - break; + + if (e->getLogId() != id) { + ++it; + continue; + } + + if (oldest && (oldest->mStart <= e->getSequence())) { + if (stats.sizes(id) > (2 * log_buffer_size(id))) { + // kick a misbehaving log reader client off the island + oldest->release_Locked(); + } else { + oldest->triggerSkip_Locked(id, pruneRows); } - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid()); - delete e; - pruneRows--; - } else { - it++; + break; } + + it = erase(it); + pruneRows--; } } @@ -487,22 +505,9 @@ uint64_t LogBuffer::flushTo( } void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) { - uint64_t oldest = UINT64_MAX; - pthread_mutex_lock(&mLogElementsLock); - // Find oldest element in the log(s) - LogBufferElementCollection::iterator it; - for (it = mLogElements.begin(); it != mLogElements.end(); ++it) { - LogBufferElement *element = *it; - - if ((logMask & (1 << element->getLogId()))) { - oldest = element->getSequence(); - break; - } - } - - stats.format(strp, uid, logMask, oldest); + stats.format(strp, uid, logMask); pthread_mutex_unlock(&mLogElementsLock); } diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 13e6aa8..a29e015 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -78,7 +78,7 @@ public: private: void maybePrune(log_id_t id); void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); - + LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it); }; #endif // _LOGD_LOG_BUFFER_H__ diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index 25f1450..0628d3e 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -17,8 +17,9 @@ #ifndef _LOGD_LOG_BUFFER_ELEMENT_H__ #define _LOGD_LOG_BUFFER_ELEMENT_H__ -#include <sys/types.h> #include <stdatomic.h> +#include <sys/types.h> + #include <sysutils/SocketClient.h> #include <log/log.h> #include <log/log_read.h> diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 5a70689..19d599c 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -14,10 +14,12 @@ * limitations under the License. */ +#include <algorithm> // std::max #include <fcntl.h> -#include <malloc.h> -#include <stdarg.h> -#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <log/logger.h> #include <private/android_filesystem_config.h> @@ -25,80 +27,21 @@ #include "LogStatistics.h" -PidStatistics::PidStatistics(pid_t pid, char *name) - : pid(pid) - , mSizesTotal(0) - , mElementsTotal(0) - , mSizes(0) - , mElements(0) - , name(name) - , mGone(false) -{ } - -#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR -PidStatistics::PidStatistics(const PidStatistics ©) - : pid(copy->pid) - , name(copy->name ? strdup(copy->name) : NULL) - , mSizesTotal(copy->mSizesTotal) - , mElementsTotal(copy->mElementsTotal) - , mSizes(copy->mSizes) - , mElements(copy->mElements) - , mGone(copy->mGone) -{ } -#endif - -PidStatistics::~PidStatistics() { - free(name); -} - -bool PidStatistics::pidGone() { - if (mGone || (pid == gone)) { - return true; - } - if (pid == 0) { - return false; - } - if (kill(pid, 0) && (errno != EPERM)) { - mGone = true; - return true; - } - return false; -} - -void PidStatistics::setName(char *new_name) { - free(name); - name = new_name; -} - -void PidStatistics::add(unsigned short size) { - mSizesTotal += size; - ++mElementsTotal; - mSizes += size; - ++mElements; -} - -bool PidStatistics::subtract(unsigned short size) { - mSizes -= size; - --mElements; - return (mElements == 0) && pidGone(); -} - -void PidStatistics::addTotal(size_t size, size_t element) { - if (pid == gone) { - mSizesTotal += size; - mElementsTotal += element; +LogStatistics::LogStatistics() { + log_id_for_each(id) { + mSizes[id] = 0; + mElements[id] = 0; + mSizesTotal[id] = 0; + mElementsTotal[id] = 0; } } -// must call free to release return value -// If only we could sniff our own logs for: -// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid> -// which debuggerd prints as a process is crashing. -char *PidStatistics::pidToName(pid_t pid) { +// caller must own and free character string +char *LogStatistics::pidToName(pid_t pid) { char *retval = NULL; if (pid == 0) { // special case from auditd for kernel retval = strdup("logd.auditd"); - } else if (pid != gone) { + } else { char buffer[512]; snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); int fd = open(buffer, O_RDONLY); @@ -117,358 +60,105 @@ char *PidStatistics::pidToName(pid_t pid) { return retval; } -UidStatistics::UidStatistics(uid_t uid) - : uid(uid) - , mSizes(0) - , mElements(0) { - Pids.clear(); -} - -UidStatistics::~UidStatistics() { - PidStatisticsCollection::iterator it; - for (it = begin(); it != end();) { - delete (*it); - it = erase(it); - } -} +void LogStatistics::add(LogBufferElement *e) { + log_id_t log_id = e->getLogId(); + unsigned short size = e->getMsgLen(); + mSizes[log_id] += size; + ++mElements[log_id]; -void UidStatistics::add(unsigned short size, pid_t pid) { - mSizes += size; - ++mElements; - - PidStatistics *p = NULL; - PidStatisticsCollection::iterator last; - PidStatisticsCollection::iterator it; - for (last = it = begin(); it != end(); last = it, ++it) { - p = *it; - if (pid == p->getPid()) { - p->add(size); - return; - } - } - // insert if the gone entry. - bool insert_before_last = (last != it) && p && (p->getPid() == p->gone); - p = new PidStatistics(pid, pidToName(pid)); - if (insert_before_last) { - insert(last, p); + uid_t uid = e->getUid(); + android::hash_t hash = android::hash_type(uid); + uidTable_t &table = uidTable[log_id]; + ssize_t index = table.find(-1, hash, uid); + if (index == -1) { + UidEntry initEntry(uid); + initEntry.add(size); + table.add(hash, initEntry); } else { - push_back(p); + UidEntry &entry = table.editEntryAt(index); + entry.add(size); } - p->add(size); -} - -void UidStatistics::subtract(unsigned short size, pid_t pid) { - mSizes -= size; - --mElements; - - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - if (p->subtract(size)) { - size_t szsTotal = p->sizesTotal(); - size_t elsTotal = p->elementsTotal(); - delete p; - erase(it); - it = end(); - --it; - if (it == end()) { - p = new PidStatistics(p->gone); - push_back(p); - } else { - p = *it; - if (p->getPid() != p->gone) { - p = new PidStatistics(p->gone); - push_back(p); - } - } - p->addTotal(szsTotal, elsTotal); - } - return; - } - } -} - -void UidStatistics::sort() { - for (bool pass = true; pass;) { - pass = false; - PidStatisticsCollection::iterator it = begin(); - if (it != end()) { - PidStatisticsCollection::iterator lt = it; - PidStatistics *l = (*lt); - while (++it != end()) { - PidStatistics *n = (*it); - if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) { - pass = true; - erase(it); - insert(lt, n); - it = lt; - n = l; - } - lt = it; - l = n; - } - } - } -} -size_t UidStatistics::sizes(pid_t pid) { - if (pid == pid_all) { - return sizes(); - } - - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - return p->sizes(); - } - } - return 0; + mSizesTotal[log_id] += size; + ++mElementsTotal[log_id]; } -size_t UidStatistics::elements(pid_t pid) { - if (pid == pid_all) { - return elements(); - } - - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if (pid == p->getPid()) { - return p->elements(); - } - } - return 0; -} - -size_t UidStatistics::sizesTotal(pid_t pid) { - size_t sizes = 0; - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if ((pid == pid_all) || (pid == p->getPid())) { - sizes += p->sizesTotal(); - } - } - return sizes; -} +void LogStatistics::subtract(LogBufferElement *e) { + log_id_t log_id = e->getLogId(); + unsigned short size = e->getMsgLen(); + mSizes[log_id] -= size; + --mElements[log_id]; -size_t UidStatistics::elementsTotal(pid_t pid) { - size_t elements = 0; - PidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - PidStatistics *p = *it; - if ((pid == pid_all) || (pid == p->getPid())) { - elements += p->elementsTotal(); + uid_t uid = e->getUid(); + android::hash_t hash = android::hash_type(uid); + uidTable_t &table = uidTable[log_id]; + ssize_t index = table.find(-1, hash, uid); + if (index != -1) { + UidEntry &entry = table.editEntryAt(index); + if (entry.subtract(size)) { + table.removeAt(index); } } - return elements; -} - -LidStatistics::LidStatistics() { - Uids.clear(); } -LidStatistics::~LidStatistics() { - UidStatisticsCollection::iterator it; - for (it = begin(); it != end();) { - delete (*it); - it = Uids.erase(it); +// caller must own and delete UidEntry array +const UidEntry **LogStatistics::sort(size_t n, log_id id) { + if (!n) { + return NULL; } -} - -void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) { - UidStatistics *u; - UidStatisticsCollection::iterator it; - UidStatisticsCollection::iterator last; - if (uid == (uid_t) -1) { // init - uid = (uid_t) AID_ROOT; - } + const UidEntry **retval = new const UidEntry* [n]; + memset(retval, 0, sizeof(*retval) * n); - for (last = it = begin(); it != end(); last = it, ++it) { - u = *it; - if (uid == u->getUid()) { - u->add(size, pid); - if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) { - Uids.erase(it); - Uids.insert(last, u); - } - return; - } - } - u = new UidStatistics(uid); - if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) { - Uids.insert(last, u); - } else { - Uids.push_back(u); - } - u->add(size, pid); -} - -void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) { - if (uid == (uid_t) -1) { // init - uid = (uid_t) AID_ROOT; - } - - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if (uid == u->getUid()) { - u->subtract(size, pid); - return; - } - } -} - -void LidStatistics::sort() { - for (bool pass = true; pass;) { - pass = false; - UidStatisticsCollection::iterator it = begin(); - if (it != end()) { - UidStatisticsCollection::iterator lt = it; - UidStatistics *l = (*lt); - while (++it != end()) { - UidStatistics *n = (*it); - if (n->sizes() > l->sizes()) { - pass = true; - Uids.erase(it); - Uids.insert(lt, n); - it = lt; - n = l; - } - lt = it; - l = n; + uidTable_t &table = uidTable[id]; + ssize_t index = -1; + while ((index = table.next(index)) >= 0) { + const UidEntry &entry = table.entryAt(index); + size_t s = entry.getSizes(); + ssize_t i = n - 1; + while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0)); + if (++i < (ssize_t)n) { + size_t b = n - i - 1; + if (b) { + memmove(&retval[i+1], &retval[i], b * sizeof(retval[0])); } + retval[i] = &entry; } } + return retval; } -size_t LidStatistics::sizes(uid_t uid, pid_t pid) { - size_t sizes = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - sizes += u->sizes(pid); - } +// caller must own and free character string +char *LogStatistics::uidToName(uid_t uid) { + // Local hard coded favourites + if (uid == AID_LOGD) { + return strdup("auditd"); } - return sizes; -} -size_t LidStatistics::elements(uid_t uid, pid_t pid) { - size_t elements = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - elements += u->elements(pid); - } - } - return elements; -} + // Android hard coded + const struct android_id_info *info = android_ids; -size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) { - size_t sizes = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - sizes += u->sizesTotal(pid); + for (size_t i = 0; i < android_id_count; ++i) { + if (info->aid == uid) { + return strdup(info->name); } + ++info; } - return sizes; -} - -size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) { - size_t elements = 0; - UidStatisticsCollection::iterator it; - for (it = begin(); it != end(); ++it) { - UidStatistics *u = *it; - if ((uid == uid_all) || (uid == u->getUid())) { - elements += u->elementsTotal(pid); - } - } - return elements; -} - -LogStatistics::LogStatistics() - : mStatistics(false) - , start(CLOCK_MONOTONIC) { - log_id_for_each(i) { - mSizes[i] = 0; - mElements[i] = 0; - } -} - -void LogStatistics::add(unsigned short size, - log_id_t log_id, uid_t uid, pid_t pid) { - mSizes[log_id] += size; - ++mElements[log_id]; - if (!mStatistics) { - return; - } - id(log_id).add(size, uid, pid); -} - -void LogStatistics::subtract(unsigned short size, - log_id_t log_id, uid_t uid, pid_t pid) { - mSizes[log_id] -= size; - --mElements[log_id]; - if (!mStatistics) { - return; - } - id(log_id).subtract(size, uid, pid); -} - -size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).sizes(uid, pid); - } - size_t sizes = 0; - log_id_for_each(i) { - sizes += id(i).sizes(uid, pid); - } - return sizes; -} -size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).elements(uid, pid); - } - size_t elements = 0; - log_id_for_each(i) { - elements += id(i).elements(uid, pid); - } - return elements; + // No one + return NULL; } -size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).sizesTotal(uid, pid); - } - size_t sizes = 0; - log_id_for_each(i) { - sizes += id(i).sizesTotal(uid, pid); - } - return sizes; -} +static void format_line(android::String8 &output, + android::String8 &name, android::String8 &size) { + static const size_t total_len = 70; -size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) { - if (log_id != log_id_all) { - return id(log_id).elementsTotal(uid, pid); - } - size_t elements = 0; - log_id_for_each(i) { - elements += id(i).elementsTotal(uid, pid); - } - return elements; + output.appendFormat("%s%*s\n", name.string(), + (int)std::max(total_len - name.length() - 1, size.length() + 1) + size.string()); } -void LogStatistics::format(char **buf, - uid_t uid, unsigned int logMask, log_time oldest) { - static const unsigned short spaces_current = 13; +void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) { static const unsigned short spaces_total = 19; if (*buf) { @@ -476,368 +166,142 @@ void LogStatistics::format(char **buf, *buf = NULL; } - android::String8 string(" span -> size/num"); + // Report on total logging, current and for all time + + android::String8 output("size/num"); size_t oldLength; - short spaces = 2; + short spaces = 1; - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - oldLength = string.length(); + oldLength = output.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i)); - spaces += spaces_total + oldLength - string.length(); + output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id)); + spaces += spaces_total + oldLength - output.length(); + } - LidStatistics &l = id(i); - l.sort(); + spaces = 4; + output.appendFormat("\nTotal"); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - (*iu)->sort(); + log_id_for_each(id) { + if (!(logMask & (1 << id))) { + continue; } - } - - spaces = 1; - log_time t(CLOCK_MONOTONIC); - unsigned long long d; - if (mStatistics) { - d = t.nsec() - start.nsec(); - string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", - d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, - (d / NS_PER_SEC) % 60, d % NS_PER_SEC); - - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; - } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%zu/%zu", spaces, "", - sizesTotal(i), elementsTotal(i)); - spaces += spaces_total + oldLength - string.length(); + oldLength = output.length(); + if (spaces < 0) { + spaces = 0; } - spaces = 1; + output.appendFormat("%*s%zu/%zu", spaces, "", + sizesTotal(id), elementsTotal(id)); + spaces += spaces_total + oldLength - output.length(); } - d = t.nsec() - oldest.nsec(); - string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu", - d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, - (d / NS_PER_SEC) % 60, d % NS_PER_SEC); + spaces = 6; + output.appendFormat("\nNow"); - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - size_t els = elements(i); + size_t els = elements(id); if (els) { - oldLength = string.length(); + oldLength = output.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els); - spaces -= string.length() - oldLength; + output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els); + spaces -= output.length() - oldLength; } spaces += spaces_total; } - // Construct list of worst spammers by Pid - static const unsigned char num_spammers = 10; - bool header = false; + // Report on Chattiest - log_id_for_each(i) { - if (!(logMask & (1 << i))) { + // Chattiest by application (UID) + log_id_for_each(id) { + if (!(logMask & (1 << id))) { continue; } - PidStatisticsCollection pids; - pids.clear(); - - LidStatistics &l = id(i); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - UidStatistics &u = *(*iu); - PidStatisticsCollection::iterator ip; - for (ip = u.begin(); ip != u.end(); ++ip) { - PidStatistics *p = (*ip); - if (p->getPid() == p->gone) { - break; - } - - size_t mySizes = p->sizes(); - - PidStatisticsCollection::iterator q; - unsigned char num = 0; - for (q = pids.begin(); q != pids.end(); ++q) { - if (mySizes > (*q)->sizes()) { - pids.insert(q, p); - break; - } - // do we need to traverse deeper in the list? - if (++num > num_spammers) { - break; - } - } - if (q == pids.end()) { - pids.push_back(p); - } - } - } + static const size_t maximum_sorted_entries = 32; + const UidEntry **sorted = sort(maximum_sorted_entries, id); - size_t threshold = sizes(i); - if (threshold < 65536) { - threshold = 65536; + if (!sorted) { + continue; } - threshold /= 100; - - PidStatisticsCollection::iterator pt = pids.begin(); - for(int line = 0; - (pt != pids.end()) && (line < num_spammers); - ++line, pt = pids.erase(pt)) { - PidStatistics *p = *pt; + bool print = false; + for(size_t index = 0; index < maximum_sorted_entries; ++index) { + const UidEntry *entry = sorted[index]; - size_t sizes = p->sizes(); - if (sizes < threshold) { + if (!entry) { break; } - char *name = p->getName(); - pid_t pid = p->getPid(); - if (!name || !*name) { - name = pidToName(pid); - if (name) { - if (*name) { - p->setName(name); - } else { - free(name); - name = NULL; - } - } - } - - if (!header) { - string.appendFormat("\n\nChattiest clients:\n" - "log id %-*s PID[?] name", - spaces_total, "size/total"); - header = true; - } - - size_t sizesTotal = p->sizesTotal(); - - android::String8 sz(""); - if (sizes == sizesTotal) { - sz.appendFormat("%zu", sizes); - } else { - sz.appendFormat("%zu/%zu", sizes, sizesTotal); - } - - android::String8 pd(""); - pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' '); - - string.appendFormat("\n%-7s%-*s %-7s%s", - line ? "" : android_log_id_to_name(i), - spaces_total, sz.string(), pd.string(), - name ? name : ""); - } - - pids.clear(); - } - - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; - } - - header = false; - bool first = true; - - UidStatisticsCollection::iterator ut; - for(ut = id(i).begin(); ut != id(i).end(); ++ut) { - UidStatistics *up = *ut; - if ((uid != AID_ROOT) && (uid != up->getUid())) { - continue; + size_t sizes = entry->getSizes(); + if (sizes < (65536/100)) { + break; } - PidStatisticsCollection::iterator pt = up->begin(); - if (pt == up->end()) { + uid_t u = entry->getKey(); + if ((uid != AID_ROOT) && (u != uid)) { continue; } - android::String8 intermediate; - - if (!header) { - // header below tuned to match spaces_total and spaces_current - spaces = 0; - intermediate = string.format("%s: UID/PID Total size/num", - android_log_id_to_name(i)); - string.appendFormat("\n\n%-31sNow " - "UID/PID[?] Total Now", - intermediate.string()); - intermediate.clear(); - header = true; - } - - bool oneline = ++pt == up->end(); - --pt; - - if (!oneline) { - first = true; - } else if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); - } - spaces = 0; - - uid_t u = up->getUid(); - PidStatistics *pp = *pt; - pid_t p = pp->getPid(); - - if (!oneline) { - intermediate = string.format("%d", u); - } else if (p == PidStatistics::gone) { - intermediate = string.format("%d/?", u); - } else if (pp->pidGone()) { - intermediate = string.format("%d/%d?", u, p); - } else { - intermediate = string.format("%d/%d", u, p); - } - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - size_t elsTotal = up->elementsTotal(); - oldLength = string.length(); - string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal); - spaces += spaces_total + oldLength - string.length(); - - size_t els = up->elements(); - if (els == elsTotal) { - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s=", spaces, ""); - spaces = -1; - } else if (els) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; + if (!print) { + if (uid == AID_ROOT) { + output.appendFormat( + "\n\nChattiest UIDs in %s:\n", + android_log_id_to_name(id)); + android::String8 name("UID"); + android::String8 size("Size"); + format_line(output, name, size); + } else { + output.appendFormat( + "\n\nLogging for your UID in %s:\n", + android_log_id_to_name(id)); } - string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els); - spaces -= string.length() - oldLength; + print = true; } - spaces += spaces_current; - - first = !first; - if (oneline) { - continue; + android::String8 name(""); + name.appendFormat("%u", u); + char *n = uidToName(u); + if (n) { + name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n); + free(n); } - size_t gone_szs = 0; - size_t gone_els = 0; - - for(; pt != up->end(); ++pt) { - pp = *pt; - p = pp->getPid(); - - // If a PID no longer has any current logs, and is not - // active anymore, skip & report totals for gone. - elsTotal = pp->elementsTotal(); - size_t szsTotal = pp->sizesTotal(); - if (p == pp->gone) { - gone_szs += szsTotal; - gone_els += elsTotal; - continue; - } - els = pp->elements(); - bool gone = pp->pidGone(); - if (gone && (els == 0)) { - // ToDo: garbage collection: move this statistical bucket - // from its current UID/PID to UID/? (races and - // wrap around are our achilles heel). Below is - // merely lipservice to catch PIDs that were still - // around when the stats were pruned to zero. - gone_szs += szsTotal; - gone_els += elsTotal; - continue; - } - - if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); - } - spaces = 0; - - intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p); - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - oldLength = string.length(); - string.appendFormat("%zu/%zu", szsTotal, elsTotal); - spaces += spaces_total + oldLength - string.length(); - - if (els == elsTotal) { - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s=", spaces, ""); - spaces = -1; - } else if (els) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%zu/%zu", spaces, "", - pp->sizes(), els); - spaces -= string.length() - oldLength; - } - spaces += spaces_current; + android::String8 size(""); + size.appendFormat("%zu", sizes); - first = !first; - } - - if (gone_els) { - if (!first && (spaces > 0)) { - string.appendFormat("%*s", spaces, ""); - } - - intermediate = string.format("%d/?", u); - string.appendFormat(first ? "\n%-12s" : "%-12s", - intermediate.string()); - intermediate.clear(); - - spaces = spaces_total + spaces_current; - - oldLength = string.length(); - string.appendFormat("%zu/%zu", gone_szs, gone_els); - spaces -= string.length() - oldLength; - - first = !first; - } + format_line(output, name, size); } + + delete [] sorted; } - *buf = strdup(string.string()); + *buf = strdup(output.string()); } uid_t LogStatistics::pidToUid(pid_t pid) { - log_id_for_each(i) { - LidStatistics &l = id(i); - UidStatisticsCollection::iterator iu; - for (iu = l.begin(); iu != l.end(); ++iu) { - UidStatistics &u = *(*iu); - PidStatisticsCollection::iterator ip; - for (ip = u.begin(); ip != u.end(); ++ip) { - if ((*ip)->getPid() == pid) { - return u.getUid(); - } + char buffer[512]; + snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid); + FILE *fp = fopen(buffer, "r"); + if (fp) { + while (fgets(buffer, sizeof(buffer), fp)) { + int uid; + if (sscanf(buffer, "Groups: %d", &uid) == 1) { + fclose(fp); + return uid; } } + fclose(fp); } return getuid(); // associate this with the logger } diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index f892cd0..d5b8762 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -20,175 +20,60 @@ #include <sys/types.h> #include <log/log.h> -#include <log/log_read.h> -#include <utils/List.h> +#include <utils/BasicHashtable.h> + +#include "LogBufferElement.h" #define log_id_for_each(i) \ for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) -class PidStatistics { - const pid_t pid; - - // Total - size_t mSizesTotal; - size_t mElementsTotal; - // Current - size_t mSizes; - size_t mElements; - - char *name; - bool mGone; - -public: - static const pid_t gone = (pid_t) -1; - - PidStatistics(pid_t pid, char *name = NULL); - PidStatistics(const PidStatistics ©); - ~PidStatistics(); - - pid_t getPid() const { return pid; } - bool pidGone(); - char *getName() const { return name; } - void setName(char *name); - - void add(unsigned short size); - bool subtract(unsigned short size); // returns true if stats and PID gone - void addTotal(size_t size, size_t element); - - size_t sizes() const { return mSizes; } - size_t elements() const { return mElements; } - - size_t sizesTotal() const { return mSizesTotal; } - size_t elementsTotal() const { return mElementsTotal; } - - // helper - static char *pidToName(pid_t pid); -}; - -typedef android::List<PidStatistics *> PidStatisticsCollection; - -class UidStatistics { +struct UidEntry { const uid_t uid; + size_t size; - PidStatisticsCollection Pids; - - void insert(PidStatisticsCollection::iterator i, PidStatistics *p) - { Pids.insert(i, p); } - void push_back(PidStatistics *p) { Pids.push_back(p); } - - size_t mSizes; - size_t mElements; - -public: - UidStatistics(uid_t uid); - ~UidStatistics(); - - PidStatisticsCollection::iterator begin() { return Pids.begin(); } - PidStatisticsCollection::iterator end() { return Pids.end(); } - PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i) - { return Pids.erase(i); } - - uid_t getUid() { return uid; } - - void add(unsigned short size, pid_t pid); - void subtract(unsigned short size, pid_t pid); - void sort(); + UidEntry(uid_t uid):uid(uid),size(0) { } - static const pid_t pid_all = (pid_t) -1; - - // fast track current value - size_t sizes() const { return mSizes; }; - size_t elements() const { return mElements; }; - - // statistical track - size_t sizes(pid_t pid); - size_t elements(pid_t pid); - - size_t sizesTotal(pid_t pid = pid_all); - size_t elementsTotal(pid_t pid = pid_all); - - // helper - static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); } -}; - -typedef android::List<UidStatistics *> UidStatisticsCollection; - -class LidStatistics { - UidStatisticsCollection Uids; - -public: - LidStatistics(); - ~LidStatistics(); - - UidStatisticsCollection::iterator begin() { return Uids.begin(); } - UidStatisticsCollection::iterator end() { return Uids.end(); } - - void add(unsigned short size, uid_t uid, pid_t pid); - void subtract(unsigned short size, uid_t uid, pid_t pid); - void sort(); - - static const pid_t pid_all = (pid_t) -1; - static const uid_t uid_all = (uid_t) -1; - - size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all); - size_t elements(uid_t uid = uid_all, pid_t pid = pid_all); - - size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all); - size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all); + inline const uid_t&getKey() const { return uid; } + size_t getSizes() const { return size; } + inline void add(size_t s) { size += s; } + inline bool subtract(size_t s) { size -= s; return !size; } }; // Log Statistics class LogStatistics { - LidStatistics LogIds[LOG_ID_MAX]; - size_t mSizes[LOG_ID_MAX]; size_t mElements[LOG_ID_MAX]; + size_t mSizesTotal[LOG_ID_MAX]; + size_t mElementsTotal[LOG_ID_MAX]; - bool mStatistics; - - static const unsigned short mBuckets[14]; - log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])]; + // uid to size list + typedef android::BasicHashtable<uid_t, UidEntry> uidTable_t; + uidTable_t uidTable[LOG_ID_MAX]; public: - const log_time start; - LogStatistics(); - LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; } + void enableStatistics() { } - void enableStatistics() { mStatistics = true; } + void add(LogBufferElement *entry); + void subtract(LogBufferElement *entry); - void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); - void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); - void sort(); + // Caller must delete array + const UidEntry **sort(size_t n, log_id i); // fast track current value by id only size_t sizes(log_id_t id) const { return mSizes[id]; } size_t elements(log_id_t id) const { return mElements[id]; } - - // statistical track - static const log_id_t log_id_all = (log_id_t) -1; - static const uid_t uid_all = (uid_t) -1; - static const pid_t pid_all = (pid_t) -1; - - size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all); - size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all); - size_t sizes() { return sizes(log_id_all, uid_all); } - size_t elements() { return elements(log_id_all, uid_all); } - - size_t sizesTotal(log_id_t id = log_id_all, - uid_t uid = uid_all, - pid_t pid = pid_all); - size_t elementsTotal(log_id_t id = log_id_all, - uid_t uid = uid_all, - pid_t pid = pid_all); + size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; } + size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; } // *strp = malloc, balance with free - void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest); + void format(char **strp, uid_t uid, unsigned int logMask); // helper - static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); } + char *pidToName(pid_t pid); uid_t pidToUid(pid_t pid); + char *uidToName(uid_t uid); }; #endif // _LOGD_LOG_STATISTICS_H__ diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h index 769d651..5f60801 100644 --- a/logd/LogWhiteBlackList.h +++ b/logd/LogWhiteBlackList.h @@ -61,7 +61,9 @@ public: int init(char *str); bool naughty(LogBufferElement *element); + bool naughty(void) { return !mNaughty.empty(); } bool nice(LogBufferElement *element); + bool nice(void) { return !mNice.empty(); } bool worstUidEnabled() const { return mWorstUidEnabled; } // *strp is malloc'd, use free to release |