527 usage = """%prog [options]
528
529 Runs a spatial analysis on a given library, looking up the source locations
530 of its symbols and calculating how much space each directory, source file,
531 and so on is taking. The result is a report that can be used to pinpoint
532 sources of large portions of the binary, etceteras.
533
534 Under normal circumstances, you only need to pass two arguments, thusly:
535
536 %prog --library /path/to/library --destdir /path/to/output
537
538 In this mode, the program will dump the symbols from the specified library
539 and map those symbols back to source locations, producing a web-based
540 report in the specified output directory.
541
542 Other options are available via '--help'.
543 """
544 parser = optparse.OptionParser(usage=usage)
545 parser.add_option(
546 '--nm-in',
547 metavar='PATH',
548 help='if specified, use nm input from <path> instead of '
549 'generating it. Note that source locations should be '
550 'present in the file; i.e., no addr2line symbol lookups '
551 'will be performed when this option is specified. '
552 'Mutually exclusive with --library.')
553 parser.add_option(
554 '--destdir',
555 metavar='PATH',
556 help='write output to the specified directory. An HTML '
557 'report is generated here along with supporting files; '
558 'any existing report will be overwritten.')
559 parser.add_option(
560 '--library',
561 metavar='PATH',
562 help='if specified, process symbols in the library at '
563 'the specified path. Mutually exclusive with --nm-in.')
564 parser.add_option(
565 '--pak',
566 metavar='PATH',
567 help='if specified, includes the contents of the '
568 'specified *.pak file in the output.')
569 parser.add_option(
570 '--nm-binary',
571 help='use the specified nm binary to analyze library. '
572 'This is to be used when the nm in the path is not for '
573 'the right architecture or of the right version.')
574 parser.add_option(
575 '--addr2line-binary',
576 help='use the specified addr2line binary to analyze '
577 'library. This is to be used when the addr2line in '
578 'the path is not for the right architecture or '
579 'of the right version.')
580 parser.add_option(
581 '--jobs',
582 type='int',
583 help='number of jobs to use for the parallel '
584 'addr2line processing pool; defaults to 1. More '
585 'jobs greatly improve throughput but eat RAM like '
586 'popcorn, and take several gigabytes each. Start low '
587 'and ramp this number up until your machine begins to '
588 'struggle with RAM. '
589 'This argument is only valid when using --library.')
590 parser.add_option(
591 '-v',
592 '--verbose',
593 dest='verbose',
594 action='store_true',
595 help='be verbose, printing lots of status information.')
596 parser.add_option(
597 '--nm-out',
598 metavar='PATH',
599 help='(deprecated) No-op. nm.out is stored in --destdir.')
600 parser.add_option(
601 '--no-nm-out',
602 action='store_true',
603 help='do not keep the nm output file. This file is useful '
604 'if you want to see the fully processed nm output after '
605 'the symbols have been mapped to source locations, or if '
606 'you plan to run explain_binary_size_delta.py. By default '
607 'the file \'nm.out\' is placed alongside the generated '
608 'report. The nm.out file is only created when using '
609 '--library.')
610 parser.add_option(
611 '--disable-disambiguation',
612 action='store_true',
613 help='disables the disambiguation process altogether,'
614 ' NOTE: this may, depending on your toolchain, produce'
615 ' output with some symbols at the top layer if addr2line'
616 ' could not get the entire source path.')
617 parser.add_option(
618 '--source-path',
619 default='./',
620 help='the path to the source code of the output binary, '
621 'default set to current directory. Used in the'
622 ' disambiguation process.')
623 parser.add_option(
624 '--check-support',
625 dest='check_support',
626 default=True,
627 action='store_true',
628 help='Check that the version of the available tools is sufficient to '
629 'read the data from the library given by --library')
630 parser.add_option('--no-check-support',
631 action='store_false',
632 dest='check_support')
633 opts, _args = parser.parse_args()
634
635 if ((not opts.library) and
636 (not opts.nm_in)) or (opts.library and opts.nm_in):
637 parser.error('exactly one of --library or --nm-in is required')
638 if opts.nm_out:
639 print(
'WARNING: --nm-out is deprecated and has no effect.',
640 file=sys.stderr)
641 if (opts.nm_in):
642 if opts.jobs:
643 print(
'WARNING: --jobs has no effect when used with --nm-in',
644 file=sys.stderr)
645 if not opts.destdir:
646 parser.error('--destdir is a required argument')
647 if not opts.jobs:
648
649
650
651
652 opts.jobs =
max(2,
min(4, multiprocessing.cpu_count()))
653
654 if opts.addr2line_binary:
655 assert os.path.isfile(opts.addr2line_binary)
656 addr2line_binary = opts.addr2line_binary
657 else:
658 addr2line_binary = _find_in_system_path('addr2line')
659 assert addr2line_binary, 'Unable to find addr2line in the path. '\
660 'Use --addr2line-binary to specify location.'
661
662 if opts.nm_binary:
663 assert os.path.isfile(opts.nm_binary)
664 nm_binary = opts.nm_binary
665 else:
666 nm_binary = _find_in_system_path('nm')
667 assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\
668 'to specify location.'
669
670 if opts.pak:
671 assert os.path.isfile(opts.pak), 'Could not find ' % opts.pak
672
673 print(
'addr2line: %s' % addr2line_binary)
674 print(
'nm: %s' % nm_binary)
675
676 if opts.library and opts.check_support:
678
679
680 if not os.path.exists(opts.destdir):
681 os.makedirs(opts.destdir, 0o755)
682 nm_out = os.path.join(opts.destdir, 'nm.out')
683 if opts.no_nm_out:
684 nm_out = None
685
686
687
688
689 data_js_file_name = os.path.join(opts.destdir, 'data.js')
690 d3_out = os.path.join(opts.destdir, 'd3')
691 if not os.path.exists(d3_out):
692 os.makedirs(d3_out, 0o755)
693 d3_src = os.path.join(os.path.dirname(__file__), '..', '..', 'd3', 'src')
694 template_src = os.path.join(os.path.dirname(__file__), 'template')
695 shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
696 shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
697 shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
698 shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
699
700
701 symbols =
GetNmSymbols(opts.nm_in, nm_out, opts.library, opts.jobs,
702 opts.verbose is True, addr2line_binary, nm_binary,
703 opts.disable_disambiguation is None,
704 opts.source_path)
705
706
707 if opts.pak:
709 if opts.library:
710 symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library))
711 else:
712
713 symbol_path_origin_dir = os.path.abspath(os.getcwd())
714
716 print(
'Report saved to ' + opts.destdir +
'/index.html')
717
718
static float max(float r, float g, float b)
static float min(float r, float g, float b)
def GetNmSymbols(nm_infile, outfile, library, jobs, verbose, addr2line_binary, nm_binary, disambiguate, src_path)