Hmm. Mostly I use "objdump --syms" and chew on the output with a ruby
script.

Here is the script, it's way too specific to our project to be
reusable, and it chews on the output of gcc 2.95 sparc tools.

But you could tweak it (lots)....

Some hints...

We had a particular interest in certain symbols with the name
"dspstd" hence the flocks of extra code in looking at that. Ignore
everything to do with dspstd, just chop it out. (Or use the code for
watching special classes of symbols)

Note the use of gdb (write a command file, run gdb, parse result) to
look inside the executable to find certain compiler computed values.

======================================================================
#!/usr/bin/ruby -w

require 'fileutils'
require 'pp'


if ENV.has_key? "TMPDIR"
  TMPDIR = ENV["TMPDIR"]
else
  TMPDIR = "/tmp"
end


def print_help_and_exit(plaint="Usage:-")
  puts "
#{plaint}

#{File.basename(__FILE__)} [options] ELF_EXECUTABLE+

Computes all static size metrics it can for tha executable.

-? --help This message
"
  exit(1)
end

class Hash
  def keys_sorted_by_value
    keys.sort_by{|k| fetch(k)}
  end

  def top_keys_by_value(too_small)
    keys.find_all{|k| fetch(k) >= too_small}.sort_by{|k| fetch(k)}
  end

end

class ResourceUtilization

  def initialize( elf, too_small_ram = 512, too_small_rom = 1024, 
too_small_dspstd=100)
    @elf = elf
    @too_small_ram = too_small_ram
    @too_small_rom = too_small_rom
    @too_small_dspstd = too_small_dspstd
    @ram = {}
    @rom = {}
    @dspstd = {}
  end

  def elf_size( elf_size = File.read("|sparc-rtems-size [EMAIL PROTECTED]"))
    raise "Size output syntax error" unless
elf_size =~ %r{ ^ \s+ text \s+ data \s+ bss \s+ dec\s+ hex \s+ filename \n
\s* (\d+) \s+ (\d+) \s+ (\d+) \s+ (\d+) \s+ ([0-9a-fA-F]+) \s .*? [EMAIL 
PROTECTED] }x

    @text, @data, @bss, dec, hex = $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.hex

    raise "Unexpected values dec #{dec} != hex #{hex}" unless
      dec == hex

  end

  def report( io)

    io.printf( "
[EMAIL 
PROTECTED](%r{#{ENV['HOME']}/|TaitTerm_Base/bld/leon/rom/uninstrumented/},'')}
Text segment: %7.2f Kb
Data segment: %7.2f Kb
BSS  segment: %7.2f Kb

Code & Data
Rom Usage : %7.2f Kb
Ram Usage : %7.2f Kb

Total Database partition usage : %7d bytes

Greediest ram symbols >= [EMAIL PROTECTED]
",
               @text/1024.0, @data/1024.0, @bss/1024.0,
               (@[EMAIL PROTECTED])/1024.0, (@[EMAIL PROTECTED])/1024.0,
               @dspstd_total
               )

    @ram.top_keys_by_value(@too_small_ram).each do |symbol|
      size = @ram[symbol]
      printf( "%50s\t%7.4f Kb\n", symbol, size / 1024.0)
    end

    puts "
Greediest rom consuming symbols >= [EMAIL PROTECTED]"
    @rom.top_keys_by_value(@too_small_rom).each do |symbol|
      size = @rom[symbol]
      printf( "%50s\t%7.4f Kb\n", symbol, size / 1024.0)
    end

    puts "
Greediest Persistent data partition consuming symbols >= [EMAIL PROTECTED]"
    @dspstd.top_keys_by_value(@too_small_dspstd).each do |symbol|
      size = @dspstd[symbol]
      printf( "%50s\t%7d bytes\n",
              symbol.sub(%r{LINK_TIME_DESIGNATED_ITEM_dspstd_},''),
              size)
    end

    puts ""
  end

  NONE  = 0
  ROM = 1
  RAM   = 2

  SEGMENTS = {
    '*ABS*' => NONE,
    '*UND*' => NONE,
    '.bss'  => RAM,
    '.data' => ROM | RAM,
    '.f_entry' => ROM,
    '.fini'    => ROM,
    '.fixup'   => ROM,
    '.gcc_except_table' => ROM | RAM,
    '.leoncodef' => ROM,
    '.rodata'    => ROM,
    '.rodata1'   => ROM,
    '.rom_vectors' => ROM,
    '.romram'  => ROM | RAM,
    '.stab'    => NONE,
    '.stabstr' => NONE,
    '.text'    => ROM,
    'check_fits_rom' => NONE}

  SEGMENTS_REGEX = "(#{SEGMENTS.keys.sort.join("|")})".gsub(%r{([.*])}, 
'\\\\\1')

  def elf_syms(elf_io = open( "|sparc-rtems-objdump --syms [EMAIL PROTECTED]"))
    elf_io.each do |line|
#12345678               12345678
#000dd7a0 l     F .text 0000003c 
pscvcp_OutgoingTransferProcessingOutgoingInfoStateAction
      if line =~ %r{ ^([0-9a-fA-F]{8}) \s+ (\S+) \s+ (.+?) \s+ 
(0[0-9a-fA-F]{7}) \s+ (.*)   }x
        address, lgw, flags, size, symbol = $1.hex, $2, $3, $4.hex, $5
        if flags =~ %r{ (?:(F|O|d|df) \s+)? #{SEGMENTS_REGEX}}x
          # puts l unless "lgw".index(l)
          flag,segment = $1, $2
          usage = SEGMENTS[segment]

          @ram[symbol] = size if usage&RAM == RAM
          @rom[symbol] = size if usage&ROM == ROM

          if symbol =~ %r{ LINK_TIME_DESIGNATED_([A-Z]+)_dspstd_(.*)  }ix
            type, sub_symbol = $1, $2
            #            p 
[type,sub_symbol,size,segment,sprintf("%x",address),address]
            #           @dspstd_ram += size
            #           @dspstd_rom += size
            if type == 'ITEM'
              #            @dspstd_rom += size
              @dspstd[symbol] = nil
            elsif type == 'HANDLE'
            elsif type == 'SERVICE'
            elsif type == 'MAXIMUM'
            else
              raise "Unexpected type '#{type}', expected one of [ITEM,HANDLE]"
            end
          end
        else
          puts "WEIRD! #{line}"
        end
      end
    end
  ensure
    elf_io.close
  end

  def dspstd_size
    command_file = "#{TMPDIR}/gdb_command.#{Process.pid}"
    syms = @dspstd.keys.sort
    open( command_file, 'w') do |cmdf|
      syms.each do |sym|
        cmdf.puts "p ((dspstd_itemConfiguration_t *)#{sym})->sizeBytes"
      end
      cmdf.puts "quit"
    end

    gdb = "sparc-rtems-gdb --quiet --nx --batch --command=#{command_file} [EMAIL 
PROTECTED]"
    result = `#{gdb}`

    i = 1

    @dspstd_total = 0
    result.scan(%r{\$ (\d+) \s+=\s+ (\d+)\n}x) do |match|
      j = $1.to_i
      sizeBytes = $2.to_i
      raise "gdb output syntax error expected '#{i} = sizeBytes, got $0" unless
        i == j
      @dspstd[syms[i-1]] = sizeBytes
      @dspstd_total += sizeBytes
      i += 1
    end
  end
end


print_help_and_exit( "Insufficient arguments") if ARGV.length <= 0
arg = ARGV.shift

print_help_and_exit if arg =~ %r{ ^--?(\?|h(e(lp?)?)?) $  }x

ARGV.unshift arg
ARGV.each do |arg|
  ru = ResourceUtilization.new(arg)

  ru.elf_size
  ru.elf_syms
  ru.dspstd_size
  ru.report(STDOUT)
end



On Mon, 21 May 2007, Chris Bayley wrote:

Hi team, I am looking for a utility that will give me a really powerful
look into the memory usage of my elf binaries
What I want to do is something like this:
   first extract all the symbols and size information using nm -S,
   then graph the information with an expression in section terms ie
(.text|.rodata) vs. an expression in symbol terms ie. symbols starting
('rtos_[.+]|gui_[.+])
   thus the above example would show me the combined ROM useage of all
the sybols being with 'rtos_' or 'gui_'.
even cooler would be then to present the information in a pie chart
fromat like 'filelight' or konqueror's 'radial view' does with the
ability to drill down and look in more detail at a given area.

If you are a programmer and can identify the need I refer to above what
are the tools you are already using to glen this kind of analysis of
memory usage in your programs ??

What I am aiming at here is a powerful tool which will help show me
where to take a scalpel to a slightly overweight binary constructed from
1000 objects.

Regards,
Chris




John Carter                             Phone : (64)(3) 358 6639
Tait Electronics                        Fax   : (64)(3) 359 4632
PO Box 1645 Christchurch                Email : [EMAIL PROTECTED]
New Zealand

Reply via email to