blob: 50ce442bbfd39b40319c53efdf5b7af93556dacd [file] [log] [blame]
Mark Salyzyn34facab2014-02-06 14:48:50 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdarg.h>
18#include <time.h>
19
20#include <log/logger.h>
21#include <private/android_filesystem_config.h>
22#include <utils/String8.h>
23
24#include "LogStatistics.h"
25
26PidStatistics::PidStatistics(pid_t pid)
27 : pid(pid)
28 , mSizesTotal(0)
29 , mElementsTotal(0)
30 , mSizes(0)
31 , mElements(0) { }
32
33void PidStatistics::add(unsigned short size) {
34 mSizesTotal += size;
35 ++mElementsTotal;
36 mSizes += size;
37 ++mElements;
38}
39
40bool PidStatistics::subtract(unsigned short size) {
41 mSizes -= size;
42 --mElements;
43 return mElements == 0 && kill(pid, 0);
44}
45
46void PidStatistics::addTotal(size_t size, size_t element) {
47 if (pid == gone) {
48 mSizesTotal += size;
49 mElementsTotal += element;
50 }
51}
52
53UidStatistics::UidStatistics(uid_t uid)
54 : uid(uid) {
55 Pids.clear();
56}
57
58UidStatistics::~UidStatistics() {
59 PidStatisticsCollection::iterator it;
60 for (it = begin(); it != end();) {
61 delete (*it);
62 it = Pids.erase(it);
63 }
64}
65
66void UidStatistics::add(unsigned short size, pid_t pid) {
67 PidStatistics *p;
68 PidStatisticsCollection::iterator last;
69 PidStatisticsCollection::iterator it;
70 for (last = it = begin(); it != end(); last = it, ++it) {
71 p = *it;
72 if (pid == p->getPid()) {
73 p->add(size);
74 // poor-man sort, bubble upwards if bigger than last
75 if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) {
76 Pids.erase(it);
77 Pids.insert(last, p);
78 }
79 return;
80 }
81 }
82 // poor-man sort, insert if bigger than last or last is the gone entry.
83 bool insert = (last != it)
84 && ((p->getPid() == p->gone)
85 || ((*last)->sizesTotal() < (size_t) size));
86 p = new PidStatistics(pid);
87 if (insert) {
88 Pids.insert(last, p);
89 } else {
90 Pids.push_back(p);
91 }
92 p->add(size);
93}
94
95void UidStatistics::subtract(unsigned short size, pid_t pid) {
96 PidStatisticsCollection::iterator it;
97 for (it = begin(); it != end(); ++it) {
98 PidStatistics *p = *it;
99 if (pid == p->getPid()) {
100 if (p->subtract(size)) {
101 size_t szsTotal = p->sizesTotal();
102 size_t elsTotal = p->elementsTotal();
103 delete p;
104 Pids.erase(it);
105 it = end();
106 --it;
107 if (it == end()) {
108 p = new PidStatistics(p->gone);
109 Pids.push_back(p);
110 } else {
111 p = *it;
112 if (p->getPid() != p->gone) {
113 p = new PidStatistics(p->gone);
114 Pids.push_back(p);
115 }
116 }
117 p->addTotal(szsTotal, elsTotal);
118 }
119 return;
120 }
121 }
122}
123
124size_t UidStatistics::sizes(pid_t pid) {
125 size_t sizes = 0;
126 PidStatisticsCollection::iterator it;
127 for (it = begin(); it != end(); ++it) {
128 PidStatistics *p = *it;
129 if ((pid == pid_all) || (pid == p->getPid())) {
130 sizes += p->sizes();
131 }
132 }
133 return sizes;
134}
135
136size_t UidStatistics::elements(pid_t pid) {
137 size_t elements = 0;
138 PidStatisticsCollection::iterator it;
139 for (it = begin(); it != end(); ++it) {
140 PidStatistics *p = *it;
141 if ((pid == pid_all) || (pid == p->getPid())) {
142 elements += p->elements();
143 }
144 }
145 return elements;
146}
147
148size_t UidStatistics::sizesTotal(pid_t pid) {
149 size_t sizes = 0;
150 PidStatisticsCollection::iterator it;
151 for (it = begin(); it != end(); ++it) {
152 PidStatistics *p = *it;
153 if ((pid == pid_all) || (pid == p->getPid())) {
154 sizes += p->sizesTotal();
155 }
156 }
157 return sizes;
158}
159
160size_t UidStatistics::elementsTotal(pid_t pid) {
161 size_t elements = 0;
162 PidStatisticsCollection::iterator it;
163 for (it = begin(); it != end(); ++it) {
164 PidStatistics *p = *it;
165 if ((pid == pid_all) || (pid == p->getPid())) {
166 elements += p->elementsTotal();
167 }
168 }
169 return elements;
170}
171
172LidStatistics::LidStatistics() {
173 Uids.clear();
174}
175
176LidStatistics::~LidStatistics() {
177 UidStatisticsCollection::iterator it;
178 for (it = begin(); it != end();) {
179 delete (*it);
180 it = Uids.erase(it);
181 }
182}
183
184void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
185 UidStatistics *u;
186 UidStatisticsCollection::iterator it;
187 UidStatisticsCollection::iterator last;
188
189 if (uid == (uid_t) -1) { // init
190 uid = (uid_t) AID_ROOT;
191 }
192
193 for (last = it = begin(); it != end(); last = it, ++it) {
194 u = *it;
195 if (uid == u->getUid()) {
196 u->add(size, pid);
197 if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
198 Uids.erase(it);
199 Uids.insert(last, u);
200 }
201 return;
202 }
203 }
204 u = new UidStatistics(uid);
205 if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
206 Uids.insert(last, u);
207 } else {
208 Uids.push_back(u);
209 }
210 u->add(size, pid);
211}
212
213void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
214 UidStatisticsCollection::iterator it;
215 for (it = begin(); it != end(); ++it) {
216 UidStatistics *u = *it;
217 if (uid == u->getUid()) {
218 u->subtract(size, pid);
219 return;
220 }
221 }
222}
223
224size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
225 size_t sizes = 0;
226 UidStatisticsCollection::iterator it;
227 for (it = begin(); it != end(); ++it) {
228 UidStatistics *u = *it;
229 if ((uid == uid_all) || (uid == u->getUid())) {
230 sizes += u->sizes(pid);
231 }
232 }
233 return sizes;
234}
235
236size_t LidStatistics::elements(uid_t uid, pid_t pid) {
237 size_t elements = 0;
238 UidStatisticsCollection::iterator it;
239 for (it = begin(); it != end(); ++it) {
240 UidStatistics *u = *it;
241 if ((uid == uid_all) || (uid == u->getUid())) {
242 elements += u->elements(pid);
243 }
244 }
245 return elements;
246}
247
248size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
249 size_t sizes = 0;
250 UidStatisticsCollection::iterator it;
251 for (it = begin(); it != end(); ++it) {
252 UidStatistics *u = *it;
253 if ((uid == uid_all) || (uid == u->getUid())) {
254 sizes += u->sizesTotal(pid);
255 }
256 }
257 return sizes;
258}
259
260size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
261 size_t elements = 0;
262 UidStatisticsCollection::iterator it;
263 for (it = begin(); it != end(); ++it) {
264 UidStatistics *u = *it;
265 if ((uid == uid_all) || (uid == u->getUid())) {
266 elements += u->elementsTotal(pid);
267 }
268 }
269 return elements;
270}
271
272LogStatistics::LogStatistics()
273 : start(CLOCK_MONOTONIC) {
274 log_id_for_each(i) {
275 mSizes[i] = 0;
276 mElements[i] = 0;
277 }
278}
279
280void LogStatistics::add(unsigned short size,
281 log_id_t log_id, uid_t uid, pid_t pid) {
282 mSizes[log_id] += size;
283 ++mElements[log_id];
284 id(log_id).add(size, uid, pid);
285}
286
287void LogStatistics::subtract(unsigned short size,
288 log_id_t log_id, uid_t uid, pid_t pid) {
289 mSizes[log_id] -= size;
290 --mElements[log_id];
291 id(log_id).subtract(size, uid, pid);
292}
293
294size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
295 if (log_id != log_id_all) {
296 return id(log_id).sizes(uid, pid);
297 }
298 size_t sizes = 0;
299 log_id_for_each(i) {
300 sizes += id(i).sizes(uid, pid);
301 }
302 return sizes;
303}
304
305size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
306 if (log_id != log_id_all) {
307 return id(log_id).elements(uid, pid);
308 }
309 size_t elements = 0;
310 log_id_for_each(i) {
311 elements += id(i).elements(uid, pid);
312 }
313 return elements;
314}
315
316size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
317 if (log_id != log_id_all) {
318 return id(log_id).sizesTotal(uid, pid);
319 }
320 size_t sizes = 0;
321 log_id_for_each(i) {
322 sizes += id(i).sizesTotal(uid, pid);
323 }
324 return sizes;
325}
326
327size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
328 if (log_id != log_id_all) {
329 return id(log_id).elementsTotal(uid, pid);
330 }
331 size_t elements = 0;
332 log_id_for_each(i) {
333 elements += id(i).elementsTotal(uid, pid);
334 }
335 return elements;
336}
337
338size_t LogStatistics::format(char **buf,
339 uid_t uid, unsigned int logMask, log_time oldest) {
340 const unsigned short spaces_current = 13;
341 const unsigned short spaces_total = 19;
342
343 if (*buf) {
344 free(buf);
345 *buf = NULL;
346 }
347
348 android::String8 string(" span -> size/num");
349 size_t oldLength;
350 short spaces = 2;
351
352 log_id_for_each(i) {
353 if (logMask & (1 << i)) {
354 oldLength = string.length();
355 string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
356 spaces += spaces_total + oldLength - string.length();
357 }
358 }
359
360 spaces = 1;
361 log_time t(CLOCK_MONOTONIC);
362 unsigned long long d = t.nsec() - start.nsec();
363 string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
364 d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
365 (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
366
367 log_id_for_each(i) {
368 if (!(logMask & (1 << i))) {
369 continue;
370 }
371 oldLength = string.length();
372 string.appendFormat("%*s%zu/%zu", spaces, "",
373 sizesTotal(i), elementsTotal(i));
374 spaces += spaces_total + oldLength - string.length();
375 }
376
377 spaces = 1;
378 d = t.nsec() - oldest.nsec();
379 string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
380 d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
381 (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
382
383 log_id_for_each(i) {
384 if (!(logMask & (1 << i))) {
385 continue;
386 }
387
388 size_t els = elements(i);
389 if (els) {
390 oldLength = string.length();
391 string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
392 spaces -= string.length() - oldLength;
393 }
394 spaces += spaces_total;
395 }
396
397 log_id_for_each(i) {
398 if (!(logMask & (1 << i))) {
399 continue;
400 }
401
402 bool header = false;
403 bool first = true;
404
405 UidStatisticsCollection::iterator ut;
406 for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
407 UidStatistics *up = *ut;
408 if ((uid != AID_ROOT) && (uid != up->getUid())) {
409 continue;
410 }
411
412 PidStatisticsCollection::iterator pt = up->begin();
413 if (pt == up->end()) {
414 continue;
415 }
416
417 android::String8 intermediate;
418
419 if (!header) {
420 // header below tuned to match spaces_total and spaces_current
421 spaces = 0;
422 intermediate = string.format("%s: UID/PID Total size/num",
423 android_log_id_to_name(i));
424 string.appendFormat("\n\n%-31sNow "
425 "UID/PID[?] Total Now",
426 intermediate.string());
427 intermediate.clear();
428 header = true;
429 }
430
431 bool oneline = ++pt == up->end();
432 --pt;
433
434 if (!oneline) {
435 first = true;
436 } else if (!first && spaces) {
437 string.appendFormat("%*s", spaces, "");
438 }
439 spaces = 0;
440
441 uid_t u = up->getUid();
442 pid_t p = (*pt)->getPid();
443
444 intermediate = string.format(oneline
445 ? ((p == PidStatistics::gone)
446 ? "%d/?"
447 : "%d/%d")
448 : "%d",
449 u, p);
450 string.appendFormat((first) ? "\n%-12s" : "%-12s",
451 intermediate.string());
452 intermediate.clear();
453
454 size_t elsTotal = up->elementsTotal();
455 oldLength = string.length();
456 string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
457 spaces += spaces_total + oldLength - string.length();
458
459 size_t els = up->elements();
460 if (els == elsTotal) {
461 string.appendFormat("%*s=", spaces, "");
462 spaces = -1;
463 } else if (els) {
464 oldLength = string.length();
465 string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
466 spaces -= string.length() - oldLength;
467 }
468 spaces += spaces_current;
469
470 first = !first;
471
472 if (oneline) {
473 continue;
474 }
475
476 size_t gone_szs = 0;
477 size_t gone_els = 0;
478
479 for(; pt != up->end(); ++pt) {
480 PidStatistics *pp = *pt;
481 pid_t p = pp->getPid();
482
483 // If a PID no longer has any current logs, and is not
484 // active anymore, skip & report totals for gone.
485 elsTotal = pp->elementsTotal();
486 size_t szsTotal = pp->sizesTotal();
487 if (p == pp->gone) {
488 gone_szs += szsTotal;
489 gone_els += elsTotal;
490 continue;
491 }
492 els = pp->elements();
493 bool gone = kill(p, 0);
494 if (gone && (els == 0)) {
495 // ToDo: garbage collection: move this statistical bucket
496 // from its current UID/PID to UID/? (races and
497 // wrap around are our achilles heel). Below is
498 // merely lipservice to catch PIDs that were still
499 // around when the stats were pruned to zero.
500 gone_szs += szsTotal;
501 gone_els += elsTotal;
502 continue;
503 }
504
505 if (!first && spaces) {
506 string.appendFormat("%*s", spaces, "");
507 }
508 spaces = 0;
509
510 intermediate = string.format((gone) ? "%d/%d?" : "%d/%d", u, p);
511 string.appendFormat((first) ? "\n%-12s" : "%-12s",
512 intermediate.string());
513 intermediate.clear();
514
515 oldLength = string.length();
516 string.appendFormat("%zu/%zu", szsTotal, elsTotal);
517 spaces += spaces_total + oldLength - string.length();
518
519 if (els == elsTotal) {
520 string.appendFormat("%*s=", spaces, "");
521 spaces = -1;
522 } else if (els) {
523 oldLength = string.length();
524 string.appendFormat("%*s%zu/%zu", spaces, "",
525 pp->sizes(), els);
526 spaces -= string.length() - oldLength;
527 }
528 spaces += spaces_current;
529
530 first = !first;
531 }
532
533 if (gone_els) {
534 if (!first && spaces) {
535 string.appendFormat("%*s", spaces, "");
536 }
537
538 intermediate = string.format("%d/?", u);
539 string.appendFormat((first) ? "\n%-12s" : "%-12s",
540 intermediate.string());
541 intermediate.clear();
542
543 spaces = spaces_total + spaces_current;
544
545 oldLength = string.length();
546 string.appendFormat("%zu/%zu", gone_szs, gone_els);
547 spaces -= string.length() - oldLength;
548
549 first = !first;
550 }
551 }
552 }
553
554 // Calculate total buffer size prefix
555 char re_fmt[32];
556 size_t ret;
557 for(size_t l = string.length(), y = 0, x = 6;
558 y != x;
559 y = x, x = strlen(re_fmt) - 2) {
560 snprintf(re_fmt, sizeof(re_fmt), "%zu\n%%s\n\f", l + x);
561 ret = l + x;
562 }
563
564 android::String8 intermediate = string.format(re_fmt, string.string());
565 string.clear();
566
567 *buf = strdup(intermediate.string());
568
569 return ret;
570}