page-analyze.cpp
1 // page-analyze.cpp -- analyze a snapshot file created by page-collect 2 // and generate specified reports. 3 // Copyright, C2009 by EQware Engineering, Inc. 4 // 5 // page-analyze.cpp is part of PageMapTools. 6 // 7 // PageMapTools is free software: you can redistribute it and/or modify 8 // it under the terms of version 3 of the GNU General Public License 9 // as published by the Free Software Foundation 10 // 11 // PageMapTools is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with PageMapTools. If not, see http://www.gnu.org/licenses. 18 // 19 20 #define _LARGEFILE64_SOURCE 21 22 #include <stddef.h> 23 #include <stdlib.h> 24 #include <stdio.h> 25 #include <assert.h> 26 #include <errno.h> 27 #include <string.h> 28 29 #include <map> 30 #include <string> 31 #include <vector> 32 33 #define FILENAMELEN 256 34 #define LINELEN 256 35 #define PAGE_SIZE 4096 36 #define MB 0x100000 37 38 #define IN_NAME "./page-collect.dat" 39 #define OUT_NAME "./page-analyze.dat" 40 41 #define FLAGS_IN_MB 0x00000001 42 #define FLAGS_COMPONENT_RPT 0x00000010 43 #define FLAGS_PROCESS_RPT 0x00000020 44 #define FLAGS_PROCVSCOMP_RPT 0x00000040 45 #define FLAGS_CSV_FMT 0x00010000 46 47 48 //class mem_stats_t -- 49 // 50 class mem_stats_t 51 { 52 public: 53 unsigned long long uss; 54 double pss; 55 unsigned long long rss; 56 unsigned long long vss; 57 58 mem_stats_t() { uss = rss = vss = 0; pss = 0.0; } 59 60 }; //class mem_stats_t 61 62 63 //class proc_mem_t -- 64 // 65 class proc_mem_t 66 { 67 public: 68 std::string name; 69 mem_stats_t stats; 70 unsigned comp_usage[200]; 71 72 proc_mem_t() 73 { name = ""; 74 memset(&stats, 0, sizeof(stats)); 75 memset(comp_usage, 0, sizeof(comp_usage)); 76 } 77 proc_mem_t(std::string p, mem_stats_t &s) 78 { name = p; 79 stats = s; 80 memset(comp_usage, 0, sizeof(comp_usage)); 81 } 82 }; //class proc_mem_t 83 84 85 //ERR() -- 86 // 87 #define ERR(format, ...) fprintf(stderr, format, ## __VA_ARGS__) 88 89 90 //is_switch() -- Returns true if the character c is a switch character, false otherwise. 91 // 92 static inline bool is_switch(char c) 93 { return c == '-'; 94 } 95 96 97 //comp_pair_uss_gt() -- 98 // 99 static bool comp_pair_uss_gt(const std::pair<std::string, const mem_stats_t *> &a, 100 const std::pair<std::string, const mem_stats_t *> &b) 101 { 102 return (a.second->uss > b.second->uss); 103 104 } //comp_pair_uss_gt(const std::pair<std::string, const mem_stats_t *> &, 105 // const std::pair<std::string, const mem_stats_t *> &) 106 107 108 //proc_mem_uss_gt() -- 109 // 110 static bool proc_mem_uss_gt(const proc_mem_t *a, const proc_mem_t *b) 111 { 112 return (a->stats.uss > b->stats.uss); 113 114 } //proc_mem_uss_gt(const proc_mem_t *, const proc_mem_t *) 115 116 117 //make_short_name() -- 118 // 119 static void make_short_name(char *buf, const char *long_name) 120 { 121 const char *b = strrchr(long_name, '/'); 122 if (b == NULL) 123 { 124 b = long_name; 125 if (*b == '0') 126 { 127 b = "ANON"; 128 } 129 else if (*b == '[') 130 { 131 b++; 132 if (strchr(b, ']') != NULL) 133 { 134 *strchr(b, ']') = '0'; 135 } 136 } 137 } 138 else 139 { 140 b++; 141 } 142 143 strcpy(buf, b); 144 buf[5] = '0'; 145 146 } //make_short_name(char *, const char *) 147 148 149 //print_report_line() -- 150 // 151 static void print_report_line(FILE *out, unsigned long flags, 152 unsigned long long uss, double pss, 153 unsigned long long rss, unsigned long long vss, 154 const char *info) 155 { 156 if (flags & FLAGS_IN_MB) 157 { 158 fprintf(out, "%10.2lf %12.2lf %10.2lf %10.2lf : %sn", 159 double(uss * PAGE_SIZE) / MB, 160 double(pss * PAGE_SIZE) / MB, 161 double(rss * PAGE_SIZE) / MB, 162 double(vss * PAGE_SIZE) / MB, 163 info); 164 } 165 else 166 { 167 fprintf(out, "%10llu %12.2lf %10llu %10llu : %sn", 168 uss, 169 pss, 170 rss, 171 vss, 172 info); 173 } 174 } //print_report_line(FILE *, unsigned long, unsigned long long, double, 175 // unsigned long long, unsigned long long, const char *) 176 177 178 //build_phys_page_usage_map() -- Build an associative array consisting of a count 179 // of references for each mapped physical page. 180 // 181 static void build_phys_page_usage_map(FILE *in, unsigned long flags, 182 std::map<unsigned long long, unsigned> &pa_map) 183 { 184 char line[LINELEN]; 185 186 assert(in != NULL); 187 188 //For each physical page mapping entry in the input file... 189 // 190 while (fgets(line, LINELEN, in) != NULL) 191 { 192 if (*line == ':') 193 { 194 //...increment the entry in the pa_map tree (create 195 // the entry and set to 1, initially). 196 // 197 unsigned long long pa = strtoull(line + 9, NULL, 16); 198 if (pa_map.find(pa) == pa_map.end()) 199 { 200 pa_map[pa] = 1; 201 } 202 else 203 { 204 pa_map[pa]++; 205 } 206 } 207 } 208 } ///build_phys_page_usage_map(FILE *, unsigned long, 209 // std:map<unsigned long long, unsigned> &) 210 211 212 //generate_process_report() -- Output a per-process report, giving the memory usage 213 // for each process. Output consists of: 214 // USS (Unique Set Size) -- the number of mapped physical pages which are 215 // referenced ONLY by the associated process. 216 // PSS (Proportional Set Size) -- the number of mapped physical pages which are 217 // referenced by the associated process, where shared pages are counted 218 // toward each process in the proportion by which they are shared. 219 // RSS (Resident Set Size) -- the number of mapped physical pages referenced by 220 // the associated process. 221 // VSS (Virtual Set Size) -- the number of pages, mapped or unmapped, which are 222 // assigned to the associated process 223 // 224 static void generate_process_report(FILE *in, FILE *out, unsigned long flags, 225 std::map<unsigned long long, unsigned> &pa_map, 226 std::map<std::string, proc_mem_t> *proc_map) 227 { 228 char line[LINELEN]; 229 char process[LINELEN]; 230 231 mem_stats_t ms; 232 mem_stats_t msc; 233 234 assert(in != NULL); 235 assert(out != NULL); 236 237 if ((flags & FLAGS_PROCESS_RPT) != 0) 238 { 239 fprintf(out, "n"); 240 fprintf(out, " USS PSS RSS Virtual : Processn"); 241 } 242 243 //For each line in the input file... 244 // 245 process[0] = '0'; 246 while (fgets(line, LINELEN, in) != NULL) 247 { 248 //If a new process entry is seen... 249 // 250 if (*line == '@') 251 { 252 unsigned j; 253 254 //Write out the previous process, including all the counters and the process string. 255 // 256 last_line: 257 if (ms.vss != 0) 258 { 259 if ((flags & FLAGS_PROCESS_RPT) != 0) 260 { 261 print_report_line(out, flags, ms.uss, ms.pss, ms.rss, ms.vss, process); 262 } 263 msc.uss += ms.uss; 264 msc.pss += ms.pss; 265 msc.rss += ms.rss; 266 msc.vss += ms.vss; 267 268 if (proc_map != NULL) 269 { 270 (*proc_map)[process].name = process + 2; 271 (*proc_map)[process].name.resize(26); 272 (*proc_map)[process].stats = ms; 273 } 274 } 275 276 //Reset to read in the new process. 277 // 278 ms.uss = 0; 279 ms.pss = 0.0; 280 ms.rss = 0; 281 ms.vss = 0; 282 283 j = strtoul(line + 8, NULL, 10); 284 sprintf(process, "%6u%s", j, strchr(line + 8, ' ')); 285 process[strlen(process) - 1] = '0'; 286 } 287 288 //If a maps file entry is seen... 289 // 290 else if (*line == '=') 291 { 292 ; //do nothing 293 } 294 295 //If a physical page address entry is seen... 296 // 297 else if (*line == ':') 298 { 299 //Get the numeric page address value. 300 // 301 unsigned long long pa = strtoull(line + 9, NULL, 16); 302 303 //Increment the appropriate counters. 304 // 305 ms.vss++; 306 if (pa != 0) 307 { 308 ms.rss++; 309 ms.pss += 1.0 / pa_map[pa]; 310 if (pa_map[pa] == 1) 311 { 312 ms.uss++; 313 } 314 } 315 } 316 317 //Should be impossible -- invalid input file. 318 // 319 else 320 { 321 assert(false); 322 } 323 } 324 325 //Write out the previous process, including all the counters and the process string. 326 // 327 if (ms.uss != 0) 328 { 329 goto last_line; 330 } 331 332 //Write out a total line. 333 // 334 if ((flags & FLAGS_PROCESS_RPT) != 0) 335 { 336 print_report_line(out, flags, msc.uss, msc.pss, msc.rss, msc.vss, 337 (flags & FLAGS_IN_MB)? " TOTAL (in MBytes)":" TOTAL (in pages)"); 338 } 339 fprintf(out, "n"); 340 341 } //generate_process_report(FILE *, FILE *, unsigned long, 342 // std::map<std::string, proc_mem_t> &, 343 // std::map<unsigned long long, unsigned> &) 344 345 346 //build_component_page_map() -- 347 // 348 static void build_component_page_map(FILE *in, unsigned long flags, 349 std::map<unsigned long long, unsigned> &pa_map, 350 std::map<std::string, mem_stats_t> &comp_map) 351 { 352 char line[LINELEN]; 353 354 mem_stats_t *ms = NULL; 355 356 assert(in != NULL); 357 358 //For each line in the input file... 359 // 360 while (fgets(line, LINELEN, in) != NULL) 361 { 362 line[strlen(line) - 1] = '0'; 363 364 //If a new process entry is seen... 365 // 366 if (*line == '@') 367 { 368 ; //do nothing 369 } 370 371 //If a maps file entry is seen... 372 // 373 else if (*line == '=') 374 { 375 //Get a pointer to the comp_map entry for this component. 376 // Create the entry if needed. 377 // 378 char *l = line + 40; //MAGIC NUMBER 379 while (*l != 'n' && !isspace(*l)) l++; 380 while (*l != 'n' && isspace(*l)) l++; 381 ms = &comp_map[l]; 382 } 383 384 //If a physical page address entry is seen... 385 // 386 else if (*line == ':') 387 { 388 assert(ms != NULL); 389 390 //Get the numeric page address value. 391 // 392 unsigned long long pa = strtoull(line + 9, NULL, 16); 393 394 //Increment the appropriate counters. 395 // 396 ms->vss++; 397 if (pa != 0) 398 { 399 ms->rss++; 400 ms->pss += 1.0 / pa_map[pa]; 401 if (pa_map[pa] == 1) 402 { 403 ms->uss++; 404 } 405 } 406 } 407 408 //Should be impossible -- invalid input file. 409 // 410 else 411 { 412 assert(false); 413 } 414 } 415 } //build_component_page_map(FILE *, unsigned long, 416 // std::map<unsigned long long, unsigned> &, 417 // std::map<std::string, mem_stats_t> &) 418 419 420 //generate_component_report() -- 421 // 422 static void generate_component_report(FILE *out, unsigned long flags, 423 std::map<std::string, mem_stats_t> &comp_map) 424 { 425 std::map<std::string, mem_stats_t>::iterator ci; 426 427 assert(out != NULL); 428 429 fprintf(out, "n"); 430 fprintf(out, " USS PSS RSS Virtual : Componentn"); 431 432 for (ci = comp_map.begin(); ci != comp_map.end(); ci++) 433 { 434 mem_stats_t *ms = &(*ci).second; 435 436 print_report_line(out, flags, ms->uss, ms->pss, ms->rss, ms->vss, 437 ((*ci).first).c_str()); 438 } 439 fprintf(out, "n"); 440 441 } //generate_component_report(FILE *, unsigned long, 442 // std::map<std::string, mem_stats_t> &) 443 444 445 //build_comp_mag_xref() -- Builds two cross-reference tables: 446 // 1. mag_comp_xref is a vector of component names/stats indexed 447 // by decreasing component USS. 448 // 2. comp_mag_xref is a map of mag_comp_xref indices, themselves indexed 449 // by component name. 450 // 451 static void build_comp_mag_xref( 452 const std::map<std::string, mem_stats_t> &comp_map, 453 std::vector< std::pair<std::string, const mem_stats_t *> > &mag_comp_xref, 454 std::map<std::string, unsigned> &comp_mag_xref) 455 { 456 //Copy all of the comp_map elements to a list. 457 // Sort the list from largest USS to smallest. 458 // 459 for (std::map<std::string, mem_stats_t>::const_iterator it = comp_map.begin(); 460 it != comp_map.end(); 461 it++) 462 { 463 mag_comp_xref.push_back(make_pair(it->first, &it->second)); 464 } 465 sort(mag_comp_xref.begin(), mag_comp_xref.end(), comp_pair_uss_gt); 466 467 //Add each mag_comp_xref string and index to comp_mag_xref. 468 // 469 for (unsigned i = 0; i < mag_comp_xref.size(); i++) 470 { 471 comp_mag_xref[mag_comp_xref[i].first] = i; 472 } 473 } //build_comp_mag_xref( 474 // const std::map<std::string, mem_stats_t> &, 475 // std::vector< std::pair<std::string, const mem_stats_t *> > &, 476 // std::map<std::string, unsigned> comp_mag_xref &) 477 478 479 //build_comp_usage_table() -- 480 // 481 static void build_comp_usage_table( 482 FILE *in, 483 unsigned flags, 484 std::map<std::string, proc_mem_t> &proc_map, 485 const std::map<std::string, unsigned> &comp_mag_xref) 486 { 487 char line[LINELEN]; 488 std::string proc = ""; 489 std::string comp = ""; 490 491 assert(in != NULL); 492 493 //For each line in the input file... 494 // 495 while (fgets(line, LINELEN, in) != NULL) 496 { 497 line[strlen(line) - 1] = '0'; 498 499 //If a new process entry is seen... 500 // 501 if (*line == '@') 502 { 503 char buf[LINELEN]; 504 unsigned j = strtoul(line + 8, NULL, 10); 505 sprintf(buf, "%6u%s", j, strchr(line + 8, ' ')); 506 proc = buf; 507 } 508 509 //If a maps file entry is seen... 510 // 511 else if (*line == '=') 512 { 513 //Get a pointer to the comp_map entry for this component. 514 // Create the entry if needed. 515 // 516 char *l = line + 40; //MAGIC NUMBER 517 while (*l != 'n' && !isspace(*l)) l++; 518 while (*l != 'n' && isspace(*l)) l++; 519 comp = l; 520 } 521 522 //If a physical page address entry is seen... 523 // 524 else if (*line == ':') 525 { 526 //Skip upper characters of page address. 527 //s 528 if (strtoull(line + 9, NULL, 16) != 0) 529 { 530 proc_map[proc].comp_usage[comp_mag_xref.find(comp)->second]++; 531 } 532 } 533 534 //Should be impossible -- invalid input file. 535 // 536 else 537 { 538 assert(false); 539 } 540 } 541 } //build_comp_usage_table( 542 // FILE *, 543 // unsigned, 544 // std::map<std::string, proc_mem_t> &, 545 // const std::map<std::string, unsigned> &) 546 547 548 //generate_proc_vs_comp_report() -- 549 // 550 static void generate_proc_vs_comp_report( 551 FILE *out, 552 unsigned flags, 553 const std::vector<proc_mem_t *> &proc_list, 554 const std::vector< std::pair<std::string, const mem_stats_t *> > &mag_comp_xref) 555 { 556 if ((flags & FLAGS_CSV_FMT) != 0) 557 { 558 //Header line #1: Process USS/PSS/RSS labels + Component names. 559 // 560 fprintf(out, ""PID - PROCESS NAME","USS","PSS","RSS""); 561 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 562 { 563 if (*mag_comp_xref[m].first.c_str() == '0') 564 fprintf(out, ","%s"", "[anon]"); 565 else 566 fprintf(out, ","%s"", mag_comp_xref[m].first.c_str()); 567 } 568 fprintf(out, "n"); 569 570 //Process lines: One line for each process, in form 571 // PID - Name : USS PSS RSS : comp-ref comp-ref ... 572 // 573 for (unsigned n = 0; n < proc_list.size(); n++) 574 { 575 const proc_mem_t *p = proc_list[n]; 576 577 fprintf(out, ""%s",%lld,%lf,%lld", 578 p->name.c_str(), p->stats.uss, p->stats.pss, p->stats.rss); 579 580 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 581 { 582 fprintf(out, ",%u", p->comp_usage[m]); 583 } 584 fprintf(out, "n"); 585 } 586 fprintf(out, "nn"); 587 } 588 else 589 { 590 //Header line #0: Component indices. 591 // 592 fprintf(out, " :"); 593 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 594 { 595 fprintf(out, " %5u", m + 1); 596 } 597 fprintf(out, "n"); 598 599 //Header line #1: Process USS/PSS/RSS labels + Component short-names. 600 // 601 fprintf(out, "PID - PROCESS NAME : USS PSS RSS :"); 602 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 603 { 604 char buf[LINELEN]; 605 make_short_name(buf, mag_comp_xref[m].first.c_str()); 606 fprintf(out, " %5s", buf); 607 } 608 fprintf(out, "n"); 609 610 //Separator line. 611 // 612 fprintf(out, "---- - ------------------- - ----- -------- ----- -"); 613 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 614 { 615 fprintf(out, " -----"); 616 } 617 fprintf(out, "n"); 618 619 //Process lines: One line for each process, in form 620 // PID - Name : USS PSS RSS : comp-ref comp-ref ... 621 // 622 for (unsigned n = 0; n < proc_list.size(); n++) 623 { 624 const proc_mem_t *p = proc_list[n]; 625 626 fprintf(out, "%-26s : %5lld %8.2lf %5lld :", 627 p->name.c_str(), p->stats.uss, p->stats.pss, p->stats.rss); 628 629 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 630 { 631 fprintf(out, " %5u", p->comp_usage[m]); 632 } 633 fprintf(out, "n"); 634 635 if (((n + 1) % 5) == 0) 636 { 637 //Separator line. 638 // 639 fprintf(out, "---- - ------------------- - ----- -------- ----- -"); 640 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 641 { 642 fprintf(out, " -----"); 643 } 644 fprintf(out, "n"); 645 } 646 } 647 648 //Separator line. 649 // 650 fprintf(out, "---- - ------------------- - ----- -------- ----- -"); 651 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 652 { 653 fprintf(out, " -----"); 654 } 655 fprintf(out, "n"); 656 657 //Footer line #1: Component short-names. 658 // 659 fprintf(out, " :"); 660 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 661 { 662 char buf[LINELEN]; 663 make_short_name(buf, mag_comp_xref[m].first.c_str()); 664 fprintf(out, " %5s", buf); 665 } 666 fprintf(out, "nn"); 667 668 //Legend header line #1: 669 // 670 fprintf(out, " SNAME : LONG NAMEn"); 671 for (unsigned m = 0; m < mag_comp_xref.size(); m++) 672 { 673 char buf[LINELEN]; 674 make_short_name(buf, mag_comp_xref[m].first.c_str()); 675 fprintf(out, "%3u %5s : %sn", m + 1, buf, mag_comp_xref[m].first.c_str()); 676 } 677 fprintf(out, "n"); 678 } 679 } //generate_proc_vs_comp_report( 680 // FILE *, 681 // unsigned, 682 // const std::vector<proc_mem_t *> &, 683 // const std::vector< std::pair<std::string, const mem_stats_t *> > &) 684 685 686 //main() -- 687 // 688 int main(int argc, char *argv[]) 689 { 690 int n; 691 FILE *in; 692 FILE *out; 693 std::map<unsigned long long, unsigned> pa_map; 694 std::map<std::string, mem_stats_t> comp_map; 695 std::map<std::string, unsigned> comp_mag_xref; 696 std::vector< std::pair<std::string, const mem_stats_t *> > mag_comp_xref; 697 std::map<std::string, proc_mem_t> proc_map; 698 std::vector<proc_mem_t *> proc_list; 699 700 const char *in_name = IN_NAME; 701 const char *out_name = OUT_NAME; 702 703 unsigned long flags = 0; 704 int retval = 0; 705 706 //Process command-line arguments. 707 // 708 for (n = 1; n < argc; n++) 709 { 710 char *arg = argv[n]; 711 712 if (is_switch(*arg)) 713 { 714 arg++; 715 716 if (strncmp(arg, "c", 1) == 0) 717 { 718 flags |= FLAGS_COMPONENT_RPT; 719 } 720 721 // -i in-file 722 // 723 else if (strncmp(arg, "i", 1) == 0) 724 { 725 if (arg[1] == '0') arg = argv[++n]; 726 else arg++; 727 728 in_name = arg; 729 } 730 731 // -mcsv 732 // 733 else if (strncmp(arg, "mcsv", 4) == 0) 734 { 735 flags |= (FLAGS_PROCVSCOMP_RPT|FLAGS_CSV_FMT); 736 } 737 738 // -m 739 // 740 else if (strncmp(arg, "m", 1) == 0) 741 { 742 flags |= FLAGS_PROCVSCOMP_RPT; 743 } 744 745 // -Mb 746 // 747 else if (strncmp(arg, "Mb", 2) == 0) 748 { 749 flags |= FLAGS_IN_MB; 750 } 751 752 // -o out-file 753 // 754 else if (strncmp(arg, "o", 1) == 0) 755 { 756 if (arg[1] == '0') arg = argv[++n]; 757 else arg++; 758 759 out_name = arg; 760 } 761 762 else if (strncmp(arg, "p", 1) == 0) 763 { 764 flags |= FLAGS_PROCESS_RPT; 765 } 766 767 // Unknown switch. 768 // 769 else goto usage; 770 } 771 else 772 { 773 usage: 774 fprintf(stderr, "n" 775 "page-analyze -- analyze a snapshot file created by page-collectn" 776 " and generate specified reports.n" 777 "n" 778 "usage: page-analyze {switches}n" 779 "switches:n" 780 " -c -- Generate component report.n" 781 " -i in-file -- Input file name (def=%s)n" 782 " -m -- Generate process/component matrix.n" 783 " -mcsv -- Generate matrix in CSV format.n" 784 " -Mb -- Report in Mbytes (def=pages)n" 785 " -o out-file -- Output file name (def=%s)n" 786 " -p -- Generate process report.n" 787 "n", 788 IN_NAME, 789 OUT_NAME); 790 goto done; 791 } 792 } 793 794 // Open output file for writing. 795 // 796 out = fopen(out_name, "w"); 797 if (out == NULL) 798 { 799 ERR("Unable to open file "%s" for writing (errno=%d). (1)n", out_name, errno); 800 retval = -1; 801 goto done; 802 } 803 804 // Open input file for reading. 805 // 806 in = fopen(in_name, "r"); 807 if (in == NULL) 808 { 809 ERR("Unable to open file "%s" for reading (errno=%d). (2)n", in_name, errno); 810 retval = -1; 811 goto done; 812 } 813 814 //Build a table of physical page addresses -> reference-counts for that page. 815 // 816 build_phys_page_usage_map(in, flags, pa_map); 817 818 if ((flags & (FLAGS_PROCESS_RPT|FLAGS_PROCVSCOMP_RPT)) != 0) 819 { 820 //Rewind input file. 821 // 822 n = fseek(in, 0, SEEK_SET); 823 if (n != 0) 824 { 825 ERR("Unable to rewind file "%s" for reading (errno=%d). (3)n", in_name, errno); 826 retval = -1; 827 goto done; 828 } 829 830 //Generate a report of memory usage for each process. 831 // 832 generate_process_report(in, out, flags, pa_map, &proc_map); 833 } 834 835 if ((flags & (FLAGS_COMPONENT_RPT|FLAGS_PROCVSCOMP_RPT)) != 0) 836 { 837 // Rewind input file. 838 // 839 n = fseek(in, 0, SEEK_SET); 840 if (n != 0) 841 { 842 ERR("Unable to rewind file "%s" for reading (errno=%d). (4)n", in_name, errno); 843 retval = -1; 844 goto done; 845 } 846 847 //Build a table of component names -> memory status. 848 // 849 build_component_page_map(in, flags, pa_map, comp_map); 850 851 if ((flags & FLAGS_COMPONENT_RPT) != 0) 852 { 853 //Generate a report of memory usage for each component. 854 // 855 generate_component_report(out, flags, comp_map); 856 } 857 858 if ((flags & FLAGS_PROCVSCOMP_RPT) != 0) 859 { 860 //Build component-magnitude-idx <-> component-name look-up tables. 861 // 862 build_comp_mag_xref(comp_map, mag_comp_xref, comp_mag_xref); 863 864 // Rewind input file. 865 // 866 n = fseek(in, 0, SEEK_SET); 867 if (n != 0) 868 { 869 ERR("Unable to rewind file "%s" for reading (errno=%d). (4)n", in_name, errno); 870 retval = -1; 871 goto done; 872 } 873 874 //Build the component usage table for each process. 875 // 876 build_comp_usage_table(in, flags, proc_map, comp_mag_xref); 877 878 //Build a list of pointers to process structures, sort it by decreasing USS... 879 // 880 for (std::map<std::string, proc_mem_t>::iterator it = proc_map.begin(); it != proc_map.end(); it++) 881 { 882 proc_list.push_back(&it->second); 883 } 884 sort(proc_list.begin(), proc_list.end(), proc_mem_uss_gt); 885 886 //..and use it to generate the process vs component memory usage matrix. 887 // 888 generate_proc_vs_comp_report(out, flags, proc_list, mag_comp_xref); 889 } 890 } 891 892 done: 893 if (out != NULL) 894 { 895 fclose(out); 896 } 897 if (in != NULL) 898 { 899 fclose(in); 900 } 901 return retval; 902 903 } //main(int, char *[]) 904 905 906 907