require 'find'
require 'pathname'
require 'pp'

fl = nil
source_has_glitch = Hash.new(false)
executable_has_glitch = Hash.new(false)

# Search from current working directory
Find.find( '.') do |path|
   # Pick up everythingending in .callgrind, .callgrind-N or staring with callgrind.out.*
   next unless path =~ %r{ \.callgrind (?: -\d+)? \z | \A callgrind\.out\. }x

   puts "Checking #{path}"
   array = IO.read(path).split(/\n/)

   asm = Hash.new{|hash,file_line| hash[file_line] = []}
   location = nil
   array.each_with_index do |l,i|
      case l
      when /\Acmd:\s+(\S+)/
         cmd = $1
         # Pick up the cmd: line from the callgrind format.
         if cmd !~ %r{ \A /  }x # Absolute path, assume relative to directory where
            # found
            cmd = Pathname.new( path).dirname + cmd
         end
         if FileTest.executable?( cmd.to_s)
            puts "Disassembling  #{cmd}"
            dump = `objdump -l -S #{cmd}`.split(/\n/)
            dump.each do |line|
               case line
               when %r{\A([a-zA-Z0-9_/\.\-]+:\d+)}x
                  location = $1
               else
                  asm[location] << line
               end
            end
         end
      when /\Afl=(.+)/
         fl = $1
      when %r{jcnd=(\d+)/(\d+)}
         a,b = $1.to_i,$2.to_i
         if (a <= b)
            source_has_glitch[fl] ||= false
            executable_has_glitch[path] ||= false
         else
            source_has_glitch[fl] ||= true
            executable_has_glitch[path] ||= true

            if FileTest.file?( fl)
               next_line = array[i+1]
               raise "Expected cost position #{next_line.inslect}" unless
                  next_line =~ %r{ \A (\d+) \s* \z }x
               source_line = $1.to_i
               source_file = IO.read( fl).split(/\n/)
               puts "
#{path}:#{i+1}: #{a}/#{b}
#{fl}:#{source_line}: #{source_file[source_line-1]}
"
               fline = "#{fl}:#{source_line}"
               puts fline
               if asm.has_key? fline
                  puts asm[fline].join("\n")
               end
            end
         end
      end

      i += 1
   end
end

j = 0
puts "=#{j}"*30, "\nExecutables without glitches"
puts executable_has_glitch.keys.find_all{|f| !executable_has_glitch[f]}.sort.join("\n")

j += 1
puts "=#{j}"*30, "\nExecutables with glitches"
puts executable_has_glitch.keys.find_all{|f| executable_has_glitch[f]}.sort.join("\n")

j += 1
puts "=#{j}"*30,"Sources without glitches"
puts source_has_glitch.keys.find_all{|f| !source_has_glitch[f]}.sort.join("\n")

j += 1
puts "=#{j}"*30, "\nSources with glitches"
puts source_has_glitch.keys.find_all{|f| source_has_glitch[f]}.sort.join("\n")
