LogStatistics.cpp revision 8e72c5384b288bc11af60e12686a44e502633e3d
1/* 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 <fcntl.h> 18#include <stdarg.h> 19#include <time.h> 20 21#include <log/logger.h> 22#include <private/android_filesystem_config.h> 23#include <utils/String8.h> 24 25#include "LogStatistics.h" 26 27PidStatistics::PidStatistics(pid_t pid, char *name) 28 : pid(pid) 29 , mSizesTotal(0) 30 , mElementsTotal(0) 31 , mSizes(0) 32 , mElements(0) 33 , name(name) 34{ } 35 36#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR 37PidStatistics::PidStatistics(const PidStatistics ©) 38 : pid(copy->pid) 39 , name(copy->name ? strdup(copy->name) : NULL) 40 , mSizesTotal(copy->mSizesTotal) 41 , mElementsTotal(copy->mElementsTotal) 42 , mSizes(copy->mSizes) 43 , mElements(copy->mElements) 44{ } 45#endif 46 47PidStatistics::~PidStatistics() { 48 free(name); 49} 50 51void PidStatistics::setName(char *new_name) { 52 free(name); 53 name = new_name; 54} 55 56void PidStatistics::add(unsigned short size) { 57 mSizesTotal += size; 58 ++mElementsTotal; 59 mSizes += size; 60 ++mElements; 61} 62 63bool PidStatistics::subtract(unsigned short size) { 64 mSizes -= size; 65 --mElements; 66 return (mElements == 0) && kill(pid, 0) && (errno != EPERM); 67} 68 69void PidStatistics::addTotal(size_t size, size_t element) { 70 if (pid == gone) { 71 mSizesTotal += size; 72 mElementsTotal += element; 73 } 74} 75 76// must call free to release return value 77char *PidStatistics::pidToName(pid_t pid) { 78 char *retval = NULL; 79 if (pid != PidStatistics::gone) { 80 char buffer[512]; 81 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); 82 int fd = open(buffer, O_RDONLY); 83 if (fd >= 0) { 84 ssize_t ret = read(fd, buffer, sizeof(buffer)); 85 if (ret > 0) { 86 buffer[sizeof(buffer)-1] = '\0'; 87 // frameworks intermediate state 88 if (strcmp(buffer, "<pre-initialized>")) { 89 retval = strdup(buffer); 90 } 91 } 92 close(fd); 93 } 94 } 95 return retval; 96} 97 98UidStatistics::UidStatistics(uid_t uid) 99 : uid(uid) { 100 Pids.clear(); 101} 102 103UidStatistics::~UidStatistics() { 104 PidStatisticsCollection::iterator it; 105 for (it = begin(); it != end();) { 106 delete (*it); 107 it = Pids.erase(it); 108 } 109} 110 111void UidStatistics::add(unsigned short size, pid_t pid) { 112 PidStatistics *p; 113 PidStatisticsCollection::iterator last; 114 PidStatisticsCollection::iterator it; 115 for (last = it = begin(); it != end(); last = it, ++it) { 116 p = *it; 117 if (pid == p->getPid()) { 118 p->add(size); 119 // poor-man sort, bubble upwards if bigger than last 120 if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) { 121 Pids.erase(it); 122 Pids.insert(last, p); 123 } 124 return; 125 } 126 } 127 // poor-man sort, insert if bigger than last or last is the gone entry. 128 bool insert = (last != it) 129 && ((p->getPid() == p->gone) 130 || ((*last)->sizesTotal() < (size_t) size)); 131 p = new PidStatistics(pid, pidToName(pid)); 132 if (insert) { 133 Pids.insert(last, p); 134 } else { 135 Pids.push_back(p); 136 } 137 p->add(size); 138} 139 140void UidStatistics::subtract(unsigned short size, pid_t pid) { 141 PidStatisticsCollection::iterator it; 142 for (it = begin(); it != end(); ++it) { 143 PidStatistics *p = *it; 144 if (pid == p->getPid()) { 145 if (p->subtract(size)) { 146 size_t szsTotal = p->sizesTotal(); 147 size_t elsTotal = p->elementsTotal(); 148 delete p; 149 Pids.erase(it); 150 it = end(); 151 --it; 152 if (it == end()) { 153 p = new PidStatistics(p->gone); 154 Pids.push_back(p); 155 } else { 156 p = *it; 157 if (p->getPid() != p->gone) { 158 p = new PidStatistics(p->gone); 159 Pids.push_back(p); 160 } 161 } 162 p->addTotal(szsTotal, elsTotal); 163 } 164 return; 165 } 166 } 167} 168 169size_t UidStatistics::sizes(pid_t pid) { 170 size_t sizes = 0; 171 PidStatisticsCollection::iterator it; 172 for (it = begin(); it != end(); ++it) { 173 PidStatistics *p = *it; 174 if ((pid == pid_all) || (pid == p->getPid())) { 175 sizes += p->sizes(); 176 } 177 } 178 return sizes; 179} 180 181size_t UidStatistics::elements(pid_t pid) { 182 size_t elements = 0; 183 PidStatisticsCollection::iterator it; 184 for (it = begin(); it != end(); ++it) { 185 PidStatistics *p = *it; 186 if ((pid == pid_all) || (pid == p->getPid())) { 187 elements += p->elements(); 188 } 189 } 190 return elements; 191} 192 193size_t UidStatistics::sizesTotal(pid_t pid) { 194 size_t sizes = 0; 195 PidStatisticsCollection::iterator it; 196 for (it = begin(); it != end(); ++it) { 197 PidStatistics *p = *it; 198 if ((pid == pid_all) || (pid == p->getPid())) { 199 sizes += p->sizesTotal(); 200 } 201 } 202 return sizes; 203} 204 205size_t UidStatistics::elementsTotal(pid_t pid) { 206 size_t elements = 0; 207 PidStatisticsCollection::iterator it; 208 for (it = begin(); it != end(); ++it) { 209 PidStatistics *p = *it; 210 if ((pid == pid_all) || (pid == p->getPid())) { 211 elements += p->elementsTotal(); 212 } 213 } 214 return elements; 215} 216 217LidStatistics::LidStatistics() { 218 Uids.clear(); 219} 220 221LidStatistics::~LidStatistics() { 222 UidStatisticsCollection::iterator it; 223 for (it = begin(); it != end();) { 224 delete (*it); 225 it = Uids.erase(it); 226 } 227} 228 229void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) { 230 UidStatistics *u; 231 UidStatisticsCollection::iterator it; 232 UidStatisticsCollection::iterator last; 233 234 if (uid == (uid_t) -1) { // init 235 uid = (uid_t) AID_ROOT; 236 } 237 238 for (last = it = begin(); it != end(); last = it, ++it) { 239 u = *it; 240 if (uid == u->getUid()) { 241 u->add(size, pid); 242 if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) { 243 Uids.erase(it); 244 Uids.insert(last, u); 245 } 246 return; 247 } 248 } 249 u = new UidStatistics(uid); 250 if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) { 251 Uids.insert(last, u); 252 } else { 253 Uids.push_back(u); 254 } 255 u->add(size, pid); 256} 257 258void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) { 259 UidStatisticsCollection::iterator it; 260 for (it = begin(); it != end(); ++it) { 261 UidStatistics *u = *it; 262 if (uid == u->getUid()) { 263 u->subtract(size, pid); 264 return; 265 } 266 } 267} 268 269size_t LidStatistics::sizes(uid_t uid, pid_t pid) { 270 size_t sizes = 0; 271 UidStatisticsCollection::iterator it; 272 for (it = begin(); it != end(); ++it) { 273 UidStatistics *u = *it; 274 if ((uid == uid_all) || (uid == u->getUid())) { 275 sizes += u->sizes(pid); 276 } 277 } 278 return sizes; 279} 280 281size_t LidStatistics::elements(uid_t uid, pid_t pid) { 282 size_t elements = 0; 283 UidStatisticsCollection::iterator it; 284 for (it = begin(); it != end(); ++it) { 285 UidStatistics *u = *it; 286 if ((uid == uid_all) || (uid == u->getUid())) { 287 elements += u->elements(pid); 288 } 289 } 290 return elements; 291} 292 293size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) { 294 size_t sizes = 0; 295 UidStatisticsCollection::iterator it; 296 for (it = begin(); it != end(); ++it) { 297 UidStatistics *u = *it; 298 if ((uid == uid_all) || (uid == u->getUid())) { 299 sizes += u->sizesTotal(pid); 300 } 301 } 302 return sizes; 303} 304 305size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) { 306 size_t elements = 0; 307 UidStatisticsCollection::iterator it; 308 for (it = begin(); it != end(); ++it) { 309 UidStatistics *u = *it; 310 if ((uid == uid_all) || (uid == u->getUid())) { 311 elements += u->elementsTotal(pid); 312 } 313 } 314 return elements; 315} 316 317LogStatistics::LogStatistics() 318 : start(CLOCK_MONOTONIC) { 319 log_id_for_each(i) { 320 mSizes[i] = 0; 321 mElements[i] = 0; 322 } 323 324 dgram_qlen_statistics = false; 325 for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) { 326 mMinimum[bucket].tv_sec = (uint32_t)-1; 327 mMinimum[bucket].tv_nsec = 999999999UL; 328 } 329} 330 331// Each bucket below represents a dgram_qlen of log messages. By 332// finding the minimum period of time from start to finish 333// of each dgram_qlen, we can get a performance expectation for 334// the user space logger. The net result is that the period 335// of time divided by the dgram_qlen will give us the average time 336// between log messages; at the point where the average time 337// is greater than the throughput capability of the logger 338// we will not longer require the benefits of the FIFO formed 339// by max_dgram_qlen. We will also expect to see a very visible 340// knee in the average time between log messages at this point, 341// so we do not necessarily have to compare the rate against the 342// measured performance (BM_log_maximum_retry) of the logger. 343// 344// for example (reformatted): 345// 346// Minimum time between log events per dgram_qlen: 347// 1 2 3 5 10 20 30 50 100 200 300 400 500 600 348// 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5 349// 350// demonstrates a clear knee rising at 100, so this means that for this 351// case max_dgram_qlen = 100 would be more than sufficient to handle the 352// worst that the system could stuff into the logger. The 353// BM_log_maximum_retry performance (derated by the log collection) on the 354// same system was 33.2us so we would almost be fine with max_dgram_qlen = 50. 355// BM_log_maxumum_retry with statistics off is roughly 20us, so 356// max_dgram_qlen = 20 would work. We will be more than willing to have 357// a large engineering margin so the rule of thumb that lead us to 100 is 358// fine. 359// 360// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 361const unsigned short LogStatistics::mBuckets[] = { 362 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600 363}; 364 365unsigned short LogStatistics::dgram_qlen(unsigned short bucket) { 366 if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) { 367 return 0; 368 } 369 return mBuckets[bucket]; 370} 371 372unsigned long long LogStatistics::minimum(unsigned short bucket) { 373 if (mMinimum[bucket].tv_sec == LONG_MAX) { 374 return 0; 375 } 376 return mMinimum[bucket].nsec(); 377} 378 379void LogStatistics::recordDiff(log_time diff, unsigned short bucket) { 380 if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) { 381 mMinimum[bucket] = diff; 382 } 383} 384 385void LogStatistics::add(unsigned short size, 386 log_id_t log_id, uid_t uid, pid_t pid) { 387 mSizes[log_id] += size; 388 ++mElements[log_id]; 389 id(log_id).add(size, uid, pid); 390} 391 392void LogStatistics::subtract(unsigned short size, 393 log_id_t log_id, uid_t uid, pid_t pid) { 394 mSizes[log_id] -= size; 395 --mElements[log_id]; 396 id(log_id).subtract(size, uid, pid); 397} 398 399size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) { 400 if (log_id != log_id_all) { 401 return id(log_id).sizes(uid, pid); 402 } 403 size_t sizes = 0; 404 log_id_for_each(i) { 405 sizes += id(i).sizes(uid, pid); 406 } 407 return sizes; 408} 409 410size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) { 411 if (log_id != log_id_all) { 412 return id(log_id).elements(uid, pid); 413 } 414 size_t elements = 0; 415 log_id_for_each(i) { 416 elements += id(i).elements(uid, pid); 417 } 418 return elements; 419} 420 421size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) { 422 if (log_id != log_id_all) { 423 return id(log_id).sizesTotal(uid, pid); 424 } 425 size_t sizes = 0; 426 log_id_for_each(i) { 427 sizes += id(i).sizesTotal(uid, pid); 428 } 429 return sizes; 430} 431 432size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) { 433 if (log_id != log_id_all) { 434 return id(log_id).elementsTotal(uid, pid); 435 } 436 size_t elements = 0; 437 log_id_for_each(i) { 438 elements += id(i).elementsTotal(uid, pid); 439 } 440 return elements; 441} 442 443void LogStatistics::format(char **buf, 444 uid_t uid, unsigned int logMask, log_time oldest) { 445 static const unsigned short spaces_current = 13; 446 static const unsigned short spaces_total = 19; 447 448 if (*buf) { 449 free(*buf); 450 *buf = NULL; 451 } 452 453 android::String8 string(" span -> size/num"); 454 size_t oldLength; 455 short spaces = 2; 456 457 log_id_for_each(i) { 458 if (logMask & (1 << i)) { 459 oldLength = string.length(); 460 if (spaces < 0) { 461 spaces = 0; 462 } 463 string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i)); 464 spaces += spaces_total + oldLength - string.length(); 465 } 466 } 467 468 spaces = 1; 469 log_time t(CLOCK_MONOTONIC); 470 unsigned long long d = t.nsec() - start.nsec(); 471 string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", 472 d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, 473 (d / NS_PER_SEC) % 60, d % NS_PER_SEC); 474 475 log_id_for_each(i) { 476 if (!(logMask & (1 << i))) { 477 continue; 478 } 479 oldLength = string.length(); 480 if (spaces < 0) { 481 spaces = 0; 482 } 483 string.appendFormat("%*s%zu/%zu", spaces, "", 484 sizesTotal(i), elementsTotal(i)); 485 spaces += spaces_total + oldLength - string.length(); 486 } 487 488 spaces = 1; 489 d = t.nsec() - oldest.nsec(); 490 string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu", 491 d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, 492 (d / NS_PER_SEC) % 60, d % NS_PER_SEC); 493 494 log_id_for_each(i) { 495 if (!(logMask & (1 << i))) { 496 continue; 497 } 498 499 size_t els = elements(i); 500 if (els) { 501 oldLength = string.length(); 502 if (spaces < 0) { 503 spaces = 0; 504 } 505 string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els); 506 spaces -= string.length() - oldLength; 507 } 508 spaces += spaces_total; 509 } 510 511 // Construct list of worst spammers by Pid 512 static const unsigned char num_spammers = 10; 513 bool header = false; 514 515 log_id_for_each(i) { 516 if (!(logMask & (1 << i))) { 517 continue; 518 } 519 520 PidStatisticsCollection pids; 521 pids.clear(); 522 523 LidStatistics &l = id(i); 524 UidStatisticsCollection::iterator iu; 525 for (iu = l.begin(); iu != l.end(); ++iu) { 526 UidStatistics &u = *(*iu); 527 PidStatisticsCollection::iterator ip; 528 for (ip = u.begin(); ip != u.end(); ++ip) { 529 PidStatistics *p = (*ip); 530 if (p->getPid() == p->gone) { 531 break; 532 } 533 534 size_t mySizes = p->sizes(); 535 536 PidStatisticsCollection::iterator q; 537 unsigned char num = 0; 538 for (q = pids.begin(); q != pids.end(); ++q) { 539 if (mySizes > (*q)->sizes()) { 540 pids.insert(q, p); 541 break; 542 } 543 // do we need to traverse deeper in the list? 544 if (++num > num_spammers) { 545 break; 546 } 547 } 548 if (q == pids.end()) { 549 pids.push_back(p); 550 } 551 } 552 } 553 554 size_t threshold = sizes(i); 555 if (threshold < 65536) { 556 threshold = 65536; 557 } 558 threshold /= 100; 559 560 PidStatisticsCollection::iterator pt = pids.begin(); 561 562 for(int line = 0; 563 (pt != pids.end()) && (line < num_spammers); 564 ++line, pt = pids.erase(pt)) { 565 PidStatistics *p = *pt; 566 567 size_t sizes = p->sizes(); 568 if (sizes < threshold) { 569 break; 570 } 571 572 char *name = p->getName(); 573 pid_t pid = p->getPid(); 574 if (!name || !*name) { 575 name = pidToName(pid); 576 if (name) { 577 if (*name) { 578 p->setName(name); 579 } else { 580 free(name); 581 name = NULL; 582 } 583 } 584 } 585 586 if (!header) { 587 string.appendFormat("\n\nChattiest clients:\n" 588 "log id %-*s PID[?] name", 589 spaces_total, "size/total"); 590 header = true; 591 } 592 593 size_t sizesTotal = p->sizesTotal(); 594 595 android::String8 sz(""); 596 sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu", 597 sizes, sizesTotal); 598 599 android::String8 pd(""); 600 pd.appendFormat("%u%c", pid, 601 (kill(pid, 0) && (errno != EPERM)) ? '?' : ' '); 602 603 string.appendFormat("\n%-7s%-*s %-7s%s", 604 line ? "" : android_log_id_to_name(i), 605 spaces_total, sz.string(), pd.string(), 606 name ? name : ""); 607 } 608 609 pids.clear(); 610 } 611 612 if (dgram_qlen_statistics) { 613 const unsigned short spaces_time = 6; 614 const unsigned long long max_seconds = 100000; 615 spaces = 0; 616 string.append("\n\nMinimum time between log events per dgram_qlen:\n"); 617 for(unsigned short i = 0; dgram_qlen(i); ++i) { 618 oldLength = string.length(); 619 if (spaces < 0) { 620 spaces = 0; 621 } 622 string.appendFormat("%*s%u", spaces, "", dgram_qlen(i)); 623 spaces += spaces_time + oldLength - string.length(); 624 } 625 string.append("\n"); 626 spaces = 0; 627 unsigned short n; 628 for(unsigned short i = 0; (n = dgram_qlen(i)); ++i) { 629 unsigned long long duration = minimum(i); 630 if (duration) { 631 duration /= n; 632 if (duration >= (NS_PER_SEC * max_seconds)) { 633 duration = NS_PER_SEC * (max_seconds - 1); 634 } 635 oldLength = string.length(); 636 if (spaces < 0) { 637 spaces = 0; 638 } 639 string.appendFormat("%*s", spaces, ""); 640 if (duration >= (NS_PER_SEC * 10)) { 641 string.appendFormat("%llu", 642 (duration + (NS_PER_SEC / 2)) 643 / NS_PER_SEC); 644 } else if (duration >= (NS_PER_SEC / (1000 / 10))) { 645 string.appendFormat("%llum", 646 (duration + (NS_PER_SEC / 2 / 1000)) 647 / (NS_PER_SEC / 1000)); 648 } else if (duration >= (NS_PER_SEC / (1000000 / 10))) { 649 string.appendFormat("%lluu", 650 (duration + (NS_PER_SEC / 2 / 1000000)) 651 / (NS_PER_SEC / 1000000)); 652 } else { 653 string.appendFormat("%llun", duration); 654 } 655 spaces -= string.length() - oldLength; 656 } 657 spaces += spaces_time; 658 } 659 } 660 661 log_id_for_each(i) { 662 if (!(logMask & (1 << i))) { 663 continue; 664 } 665 666 header = false; 667 bool first = true; 668 669 UidStatisticsCollection::iterator ut; 670 for(ut = id(i).begin(); ut != id(i).end(); ++ut) { 671 UidStatistics *up = *ut; 672 if ((uid != AID_ROOT) && (uid != up->getUid())) { 673 continue; 674 } 675 676 PidStatisticsCollection::iterator pt = up->begin(); 677 if (pt == up->end()) { 678 continue; 679 } 680 681 android::String8 intermediate; 682 683 if (!header) { 684 // header below tuned to match spaces_total and spaces_current 685 spaces = 0; 686 intermediate = string.format("%s: UID/PID Total size/num", 687 android_log_id_to_name(i)); 688 string.appendFormat("\n\n%-31sNow " 689 "UID/PID[?] Total Now", 690 intermediate.string()); 691 intermediate.clear(); 692 header = true; 693 } 694 695 bool oneline = ++pt == up->end(); 696 --pt; 697 698 if (!oneline) { 699 first = true; 700 } else if (!first && (spaces > 0)) { 701 string.appendFormat("%*s", spaces, ""); 702 } 703 spaces = 0; 704 705 uid_t u = up->getUid(); 706 pid_t p = (*pt)->getPid(); 707 708 intermediate = string.format(oneline 709 ? ((p == PidStatistics::gone) 710 ? "%d/?" 711 : "%d/%d") 712 : "%d", 713 u, p); 714 string.appendFormat(first ? "\n%-12s" : "%-12s", 715 intermediate.string()); 716 intermediate.clear(); 717 718 size_t elsTotal = up->elementsTotal(); 719 oldLength = string.length(); 720 string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal); 721 spaces += spaces_total + oldLength - string.length(); 722 723 size_t els = up->elements(); 724 if (els == elsTotal) { 725 if (spaces < 0) { 726 spaces = 0; 727 } 728 string.appendFormat("%*s=", spaces, ""); 729 spaces = -1; 730 } else if (els) { 731 oldLength = string.length(); 732 if (spaces < 0) { 733 spaces = 0; 734 } 735 string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els); 736 spaces -= string.length() - oldLength; 737 } 738 spaces += spaces_current; 739 740 first = !first; 741 742 if (oneline) { 743 continue; 744 } 745 746 size_t gone_szs = 0; 747 size_t gone_els = 0; 748 749 for(; pt != up->end(); ++pt) { 750 PidStatistics *pp = *pt; 751 pid_t p = pp->getPid(); 752 753 // If a PID no longer has any current logs, and is not 754 // active anymore, skip & report totals for gone. 755 elsTotal = pp->elementsTotal(); 756 size_t szsTotal = pp->sizesTotal(); 757 if (p == pp->gone) { 758 gone_szs += szsTotal; 759 gone_els += elsTotal; 760 continue; 761 } 762 els = pp->elements(); 763 bool gone = kill(p, 0) && (errno != EPERM); 764 if (gone && (els == 0)) { 765 // ToDo: garbage collection: move this statistical bucket 766 // from its current UID/PID to UID/? (races and 767 // wrap around are our achilles heel). Below is 768 // merely lipservice to catch PIDs that were still 769 // around when the stats were pruned to zero. 770 gone_szs += szsTotal; 771 gone_els += elsTotal; 772 continue; 773 } 774 775 if (!first && (spaces > 0)) { 776 string.appendFormat("%*s", spaces, ""); 777 } 778 spaces = 0; 779 780 intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p); 781 string.appendFormat(first ? "\n%-12s" : "%-12s", 782 intermediate.string()); 783 intermediate.clear(); 784 785 oldLength = string.length(); 786 string.appendFormat("%zu/%zu", szsTotal, elsTotal); 787 spaces += spaces_total + oldLength - string.length(); 788 789 if (els == elsTotal) { 790 if (spaces < 0) { 791 spaces = 0; 792 } 793 string.appendFormat("%*s=", spaces, ""); 794 spaces = -1; 795 } else if (els) { 796 oldLength = string.length(); 797 if (spaces < 0) { 798 spaces = 0; 799 } 800 string.appendFormat("%*s%zu/%zu", spaces, "", 801 pp->sizes(), els); 802 spaces -= string.length() - oldLength; 803 } 804 spaces += spaces_current; 805 806 first = !first; 807 } 808 809 if (gone_els) { 810 if (!first && (spaces > 0)) { 811 string.appendFormat("%*s", spaces, ""); 812 } 813 814 intermediate = string.format("%d/?", u); 815 string.appendFormat(first ? "\n%-12s" : "%-12s", 816 intermediate.string()); 817 intermediate.clear(); 818 819 spaces = spaces_total + spaces_current; 820 821 oldLength = string.length(); 822 string.appendFormat("%zu/%zu", gone_szs, gone_els); 823 spaces -= string.length() - oldLength; 824 825 first = !first; 826 } 827 } 828 } 829 830 *buf = strdup(string.string()); 831} 832 833uid_t LogStatistics::pidToUid(pid_t pid) { 834 log_id_for_each(i) { 835 LidStatistics &l = id(i); 836 UidStatisticsCollection::iterator iu; 837 for (iu = l.begin(); iu != l.end(); ++iu) { 838 UidStatistics &u = *(*iu); 839 PidStatisticsCollection::iterator ip; 840 for (ip = u.begin(); ip != u.end(); ++ip) { 841 if ((*ip)->getPid() == pid) { 842 return u.getUid(); 843 } 844 } 845 } 846 } 847 return getuid(); // associate this with the logger 848} 849