summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'logd/LogStatistics.cpp')
-rw-r--r--logd/LogStatistics.cpp324
1 files changed, 286 insertions, 38 deletions
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index cc30f7783..af59ddc25 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,7 +14,9 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include <ctype.h>
17#include <fcntl.h> 18#include <fcntl.h>
19#include <inttypes.h>
18#include <pwd.h> 20#include <pwd.h>
19#include <stdio.h> 21#include <stdio.h>
20#include <string.h> 22#include <string.h>
@@ -23,19 +25,26 @@
23 25
24#include <list> 26#include <list>
25 27
26#include <android/log.h> 28#include <private/android_logger.h>
27 29
28#include "LogStatistics.h" 30#include "LogStatistics.h"
29 31
32static const uint64_t hourSec = 60 * 60;
33static const uint64_t monthSec = 31 * 24 * hourSec;
34
30size_t LogStatistics::SizesTotal; 35size_t LogStatistics::SizesTotal;
31 36
32LogStatistics::LogStatistics() : enable(false) { 37LogStatistics::LogStatistics() : enable(false) {
38 log_time now(CLOCK_REALTIME);
33 log_id_for_each(id) { 39 log_id_for_each(id) {
34 mSizes[id] = 0; 40 mSizes[id] = 0;
35 mElements[id] = 0; 41 mElements[id] = 0;
36 mDroppedElements[id] = 0; 42 mDroppedElements[id] = 0;
37 mSizesTotal[id] = 0; 43 mSizesTotal[id] = 0;
38 mElementsTotal[id] = 0; 44 mElementsTotal[id] = 0;
45 mOldest[id] = now;
46 mNewest[id] = now;
47 mNewestDropped[id] = now;
39 } 48 }
40} 49}
41 50
@@ -70,25 +79,56 @@ char* pidToName(pid_t pid) {
70} 79}
71} 80}
72 81
82void LogStatistics::addTotal(LogBufferElement* element) {
83 if (element->getDropped()) return;
84
85 log_id_t log_id = element->getLogId();
86 unsigned short size = element->getMsgLen();
87 mSizesTotal[log_id] += size;
88 SizesTotal += size;
89 ++mElementsTotal[log_id];
90}
91
73void LogStatistics::add(LogBufferElement* element) { 92void LogStatistics::add(LogBufferElement* element) {
74 log_id_t log_id = element->getLogId(); 93 log_id_t log_id = element->getLogId();
75 unsigned short size = element->getMsgLen(); 94 unsigned short size = element->getMsgLen();
76 mSizes[log_id] += size; 95 mSizes[log_id] += size;
77 ++mElements[log_id]; 96 ++mElements[log_id];
78 97
98 // When caller adding a chatty entry, they will have already
99 // called add() and subtract() for each entry as they are
100 // evaluated and trimmed, thus recording size and number of
101 // elements, but we must recognize the manufactured dropped
102 // entry as not contributing to the lifetime totals.
79 if (element->getDropped()) { 103 if (element->getDropped()) {
80 ++mDroppedElements[log_id]; 104 ++mDroppedElements[log_id];
81 } else { 105 } else {
82 // When caller adding a chatty entry, they will have already
83 // called add() and subtract() for each entry as they are
84 // evaluated and trimmed, thus recording size and number of
85 // elements, but we must recognize the manufactured dropped
86 // entry as not contributing to the lifetime totals.
87 mSizesTotal[log_id] += size; 106 mSizesTotal[log_id] += size;
88 SizesTotal += size; 107 SizesTotal += size;
89 ++mElementsTotal[log_id]; 108 ++mElementsTotal[log_id];
90 } 109 }
91 110
111 log_time stamp(element->getRealTime());
112 if (mNewest[log_id] < stamp) {
113 // A major time update invalidates the statistics :-(
114 log_time diff = stamp - mNewest[log_id];
115 mNewest[log_id] = stamp;
116
117 if (diff.tv_sec > hourSec) {
118 // approximate Do-Your-Best fixup
119 diff += mOldest[log_id];
120 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
121 diff = stamp;
122 }
123 if (diff <= stamp) {
124 mOldest[log_id] = diff;
125 if (mNewestDropped[log_id] < diff) {
126 mNewestDropped[log_id] = diff;
127 }
128 }
129 }
130 }
131
92 if (log_id == LOG_ID_KERNEL) { 132 if (log_id == LOG_ID_KERNEL) {
93 return; 133 return;
94 } 134 }
@@ -113,6 +153,10 @@ void LogStatistics::add(LogBufferElement* element) {
113 tagTable.add(tag, element); 153 tagTable.add(tag, element);
114 } 154 }
115 } 155 }
156
157 if (!element->getDropped()) {
158 tagNameTable.add(TagNameKey(element), element);
159 }
116} 160}
117 161
118void LogStatistics::subtract(LogBufferElement* element) { 162void LogStatistics::subtract(LogBufferElement* element) {
@@ -124,6 +168,10 @@ void LogStatistics::subtract(LogBufferElement* element) {
124 --mDroppedElements[log_id]; 168 --mDroppedElements[log_id];
125 } 169 }
126 170
171 if (mOldest[log_id] < element->getRealTime()) {
172 mOldest[log_id] = element->getRealTime();
173 }
174
127 if (log_id == LOG_ID_KERNEL) { 175 if (log_id == LOG_ID_KERNEL) {
128 return; 176 return;
129 } 177 }
@@ -148,6 +196,10 @@ void LogStatistics::subtract(LogBufferElement* element) {
148 tagTable.subtract(tag, element); 196 tagTable.subtract(tag, element);
149 } 197 }
150 } 198 }
199
200 if (!element->getDropped()) {
201 tagNameTable.subtract(TagNameKey(element), element);
202 }
151} 203}
152 204
153// Atomically set an entry to drop 205// Atomically set an entry to drop
@@ -158,6 +210,10 @@ void LogStatistics::drop(LogBufferElement* element) {
158 mSizes[log_id] -= size; 210 mSizes[log_id] -= size;
159 ++mDroppedElements[log_id]; 211 ++mDroppedElements[log_id];
160 212
213 if (mNewestDropped[log_id] < element->getRealTime()) {
214 mNewestDropped[log_id] = element->getRealTime();
215 }
216
161 uidTable[log_id].drop(element->getUid(), element); 217 uidTable[log_id].drop(element->getUid(), element);
162 if (element->getUid() == AID_SYSTEM) { 218 if (element->getUid() == AID_SYSTEM) {
163 pidSystemTable[log_id].drop(element->getPid(), element); 219 pidSystemTable[log_id].drop(element->getPid(), element);
@@ -178,9 +234,12 @@ void LogStatistics::drop(LogBufferElement* element) {
178 tagTable.drop(tag, element); 234 tagTable.drop(tag, element);
179 } 235 }
180 } 236 }
237
238 tagNameTable.subtract(TagNameKey(element), element);
181} 239}
182 240
183// caller must own and free character string 241// caller must own and free character string
242// Requires parent LogBuffer::wrlock() to be held
184const char* LogStatistics::uidToName(uid_t uid) const { 243const char* LogStatistics::uidToName(uid_t uid) const {
185 // Local hard coded favourites 244 // Local hard coded favourites
186 if (uid == AID_LOGD) { 245 if (uid == AID_LOGD) {
@@ -248,18 +307,38 @@ std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
248 std::string(isprune ? "NUM" : "")); 307 std::string(isprune ? "NUM" : ""));
249} 308}
250 309
251std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const { 310// Helper to truncate name, if too long, and add name dressings
252 uid_t uid = getUid(); 311static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
253 std::string name = android::base::StringPrintf("%u", uid); 312 std::string& name, std::string& size, size_t nameLen) {
254 const char* nameTmp = stat.uidToName(uid); 313 const char* allocNameTmp = nullptr;
314 if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
255 if (nameTmp) { 315 if (nameTmp) {
256 name += android::base::StringPrintf( 316 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
257 "%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp); 317 size_t len = EntryBaseConstants::total_len -
258 free(const_cast<char*>(nameTmp)); 318 EntryBaseConstants::pruned_len - size.length() -
319 name.length() - lenSpace - 2;
320 size_t lenNameTmp = strlen(nameTmp);
321 while ((len < lenNameTmp) && (lenSpace > 1)) {
322 ++len;
323 --lenSpace;
324 }
325 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
326 if (len < lenNameTmp) {
327 name += "...";
328 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
329 }
330 name += nameTmp;
331 free(const_cast<char*>(allocNameTmp));
259 } 332 }
333}
260 334
335std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
336 uid_t uid = getUid();
337 std::string name = android::base::StringPrintf("%u", uid);
261 std::string size = android::base::StringPrintf("%zu", getSizes()); 338 std::string size = android::base::StringPrintf("%zu", getSizes());
262 339
340 formatTmp(stat, nullptr, uid, name, size, 6);
341
263 std::string pruned = ""; 342 std::string pruned = "";
264 if (worstUidEnabledForLogid(id)) { 343 if (worstUidEnabledForLogid(id)) {
265 size_t totalDropped = 0; 344 size_t totalDropped = 0;
@@ -366,18 +445,10 @@ std::string PidEntry::format(const LogStatistics& stat,
366 uid_t uid = getUid(); 445 uid_t uid = getUid();
367 pid_t pid = getPid(); 446 pid_t pid = getPid();
368 std::string name = android::base::StringPrintf("%5u/%u", pid, uid); 447 std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
369 const char* nameTmp = getName();
370 if (nameTmp) {
371 name += android::base::StringPrintf(
372 "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
373 } else if ((nameTmp = stat.uidToName(uid))) {
374 name += android::base::StringPrintf(
375 "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
376 free(const_cast<char*>(nameTmp));
377 }
378
379 std::string size = android::base::StringPrintf("%zu", getSizes()); 448 std::string size = android::base::StringPrintf("%zu", getSizes());
380 449
450 formatTmp(stat, getName(), uid, name, size, 12);
451
381 std::string pruned = ""; 452 std::string pruned = "";
382 size_t dropped = getDropped(); 453 size_t dropped = getDropped();
383 if (dropped) { 454 if (dropped) {
@@ -398,21 +469,10 @@ std::string TidEntry::format(const LogStatistics& stat,
398 log_id_t /* id */) const { 469 log_id_t /* id */) const {
399 uid_t uid = getUid(); 470 uid_t uid = getUid();
400 std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid); 471 std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
401 const char* nameTmp = getName();
402 if (nameTmp) {
403 name += android::base::StringPrintf(
404 "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
405 } else if ((nameTmp = stat.uidToName(uid))) {
406 // if we do not have a PID name, lets punt to try UID name?
407 name += android::base::StringPrintf(
408 "%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
409 free(const_cast<char*>(nameTmp));
410 // We tried, better to not have a name at all, we still
411 // have TID/UID by number to report in any case.
412 }
413
414 std::string size = android::base::StringPrintf("%zu", getSizes()); 472 std::string size = android::base::StringPrintf("%zu", getSizes());
415 473
474 formatTmp(stat, getName(), uid, name, size, 12);
475
416 std::string pruned = ""; 476 std::string pruned = "";
417 size_t dropped = getDropped(); 477 size_t dropped = getDropped();
418 if (dropped) { 478 if (dropped) {
@@ -456,6 +516,101 @@ std::string TagEntry::format(const LogStatistics& /* stat */,
456 return formatLine(name, size, pruned); 516 return formatLine(name, size, pruned);
457} 517}
458 518
519std::string TagNameEntry::formatHeader(const std::string& name,
520 log_id_t /* id */) const {
521 return formatLine(name, std::string("Size"), std::string("")) +
522 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
523 std::string("BYTES"), std::string(""));
524}
525
526std::string TagNameEntry::format(const LogStatistics& /* stat */,
527 log_id_t /* id */) const {
528 std::string name;
529 pid_t tid = getTid();
530 pid_t pid = getPid();
531 std::string pidstr;
532 if (pid != (pid_t)-1) {
533 pidstr = android::base::StringPrintf("%u", pid);
534 if ((tid != (pid_t)-1) && (tid != pid)) pidstr = "/" + pidstr;
535 }
536 int len = 9 - pidstr.length();
537 if (len < 0) len = 0;
538 if ((tid == (pid_t)-1) || (tid == pid)) {
539 name = android::base::StringPrintf("%*s", len, "");
540 } else {
541 name = android::base::StringPrintf("%*u", len, tid);
542 }
543 name += pidstr;
544 uid_t uid = getUid();
545 if (uid != (uid_t)-1) {
546 name += android::base::StringPrintf("/%u", uid);
547 }
548
549 std::string size = android::base::StringPrintf("%zu", getSizes());
550
551 const char* nameTmp = getName();
552 if (nameTmp) {
553 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
554 size_t len = EntryBaseConstants::total_len -
555 EntryBaseConstants::pruned_len - size.length() -
556 name.length() - lenSpace - 2;
557 size_t lenNameTmp = strlen(nameTmp);
558 while ((len < lenNameTmp) && (lenSpace > 1)) {
559 ++len;
560 --lenSpace;
561 }
562 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
563 if (len < lenNameTmp) {
564 name += "...";
565 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
566 }
567 name += nameTmp;
568 }
569
570 std::string pruned = "";
571
572 return formatLine(name, size, pruned);
573}
574
575static std::string formatMsec(uint64_t val) {
576 static const unsigned subsecDigits = 3;
577 static const uint64_t sec = MS_PER_SEC;
578
579 static const uint64_t minute = 60 * sec;
580 static const uint64_t hour = 60 * minute;
581 static const uint64_t day = 24 * hour;
582
583 std::string output;
584 if (val < sec) return output;
585
586 if (val >= day) {
587 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
588 val = (val % day) + day;
589 }
590 if (val >= minute) {
591 if (val >= hour) {
592 output += android::base::StringPrintf("%" PRIu64 ":",
593 (val / hour) % (day / hour));
594 }
595 output += android::base::StringPrintf(
596 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
597 (val / minute) % (hour / minute));
598 }
599 output +=
600 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
601 (val / sec) % (minute / sec));
602 val %= sec;
603 unsigned digits = subsecDigits;
604 while (digits && ((val % 10) == 0)) {
605 val /= 10;
606 --digits;
607 }
608 if (digits) {
609 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
610 }
611 return output;
612}
613
459std::string LogStatistics::format(uid_t uid, pid_t pid, 614std::string LogStatistics::format(uid_t uid, pid_t pid,
460 unsigned int logMask) const { 615 unsigned int logMask) const {
461 static const unsigned short spaces_total = 19; 616 static const unsigned short spaces_total = 19;
@@ -525,6 +680,67 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
525 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize, 680 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
526 totalEls); 681 totalEls);
527 682
683 static const char SpanStr[] = "\nLogspan";
684 spaces = 10 - strlen(SpanStr);
685 output += SpanStr;
686
687 // Total reports the greater of the individual maximum time span, or the
688 // validated minimum start and maximum end time span if it makes sense.
689 uint64_t minTime = UINT64_MAX;
690 uint64_t maxTime = 0;
691 uint64_t maxSpan = 0;
692 totalSize = 0;
693
694 log_id_for_each(id) {
695 if (!(logMask & (1 << id))) continue;
696
697 // validity checking
698 uint64_t oldest = mOldest[id].msec();
699 uint64_t newest = mNewest[id].msec();
700 if (newest <= oldest) {
701 spaces += spaces_total;
702 continue;
703 }
704
705 uint64_t span = newest - oldest;
706 if (span > (monthSec * MS_PER_SEC)) {
707 spaces += spaces_total;
708 continue;
709 }
710
711 // total span
712 if (minTime > oldest) minTime = oldest;
713 if (maxTime < newest) maxTime = newest;
714 if (span > maxSpan) maxSpan = span;
715 totalSize += span;
716
717 uint64_t dropped = mNewestDropped[id].msec();
718 if (dropped < oldest) dropped = oldest;
719 if (dropped > newest) dropped = newest;
720
721 oldLength = output.length();
722 output += android::base::StringPrintf("%*s%s", spaces, "",
723 formatMsec(span).c_str());
724 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
725 if ((permille > 1) && (permille < 999)) {
726 output += android::base::StringPrintf("(%u", permille / 10);
727 permille %= 10;
728 if (permille) {
729 output += android::base::StringPrintf(".%u", permille);
730 }
731 output += android::base::StringPrintf("%%)");
732 }
733 spaces -= output.length() - oldLength;
734 spaces += spaces_total;
735 }
736 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
737 (maxTime > maxSpan)) {
738 maxSpan = maxTime;
739 }
740 if (spaces < 0) spaces = 0;
741 output += android::base::StringPrintf("%*s%s", spaces, "",
742 formatMsec(maxSpan).c_str());
743
528 static const char OverheadStr[] = "\nOverhead"; 744 static const char OverheadStr[] = "\nOverhead";
529 spaces = 10 - strlen(OverheadStr); 745 spaces = 10 - strlen(OverheadStr);
530 output += OverheadStr; 746 output += OverheadStr;
@@ -591,6 +807,13 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
591 securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY); 807 securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
592 } 808 }
593 809
810 if (enable) {
811 name = "Chattiest TAGs";
812 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
813 name += ":";
814 output += tagNameTable.format(*this, uid, pid, name);
815 }
816
594 return output; 817 return output;
595} 818}
596 819
@@ -602,8 +825,10 @@ uid_t pidToUid(pid_t pid) {
602 FILE* fp = fopen(buffer, "r"); 825 FILE* fp = fopen(buffer, "r");
603 if (fp) { 826 if (fp) {
604 while (fgets(buffer, sizeof(buffer), fp)) { 827 while (fgets(buffer, sizeof(buffer), fp)) {
605 int uid; 828 int uid = AID_LOGD;
606 if (sscanf(buffer, "Uid: %d", &uid) == 1) { 829 char space = 0;
830 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
831 isspace(space)) {
607 fclose(fp); 832 fclose(fp);
608 return uid; 833 return uid;
609 } 834 }
@@ -612,12 +837,35 @@ uid_t pidToUid(pid_t pid) {
612 } 837 }
613 return AID_LOGD; // associate this with the logger 838 return AID_LOGD; // associate this with the logger
614} 839}
840
841pid_t tidToPid(pid_t tid) {
842 char buffer[512];
843 snprintf(buffer, sizeof(buffer), "/proc/%u/status", tid);
844 FILE* fp = fopen(buffer, "r");
845 if (fp) {
846 while (fgets(buffer, sizeof(buffer), fp)) {
847 int pid = tid;
848 char space = 0;
849 if ((sscanf(buffer, "Tgid: %d%c", &pid, &space) == 2) &&
850 isspace(space)) {
851 fclose(fp);
852 return pid;
853 }
854 }
855 fclose(fp);
856 }
857 return tid;
858}
615} 859}
616 860
617uid_t LogStatistics::pidToUid(pid_t pid) { 861uid_t LogStatistics::pidToUid(pid_t pid) {
618 return pidTable.add(pid)->second.getUid(); 862 return pidTable.add(pid)->second.getUid();
619} 863}
620 864
865pid_t LogStatistics::tidToPid(pid_t tid) {
866 return tidTable.add(tid)->second.getPid();
867}
868
621// caller must free character string 869// caller must free character string
622const char* LogStatistics::pidToName(pid_t pid) const { 870const char* LogStatistics::pidToName(pid_t pid) const {
623 // An inconvenient truth ... getName() can alter the object 871 // An inconvenient truth ... getName() can alter the object