#!/usr/bin/env ruby

$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
require 'railsbench/perf_info'

narrow = ARGV.delete('-narrow') || ARGV.delete('-n')
skip_urls = ARGV.delete('-skip_urls') || ARGV.delete('-s')

if ARGV.length < 2
  $stderr.puts "perfcomp: not enough arguments!"
  $stderr.puts "usage: perf_comp [-n[arrow]] [-s[kip_urls]] file1 file2"
  exit 1
elsif ARGV.length > 2
  $stderr.puts "perfcomp: too many arguments!"
  $stderr.puts "usage: perf_comp [-n[arrow]] [-s[kip_urls]] file1 file2"
  exit 1
end

files = []
configs = []
pi = []

ARGV.each do |arg|
  files << File.open_or_die(arg)
  pi << PerfInfo.new(files.last)
end

if pi[0].keys != pi[1].keys
  $stderr.puts "perfcomp: can't compare runs with differing requests!"
  exit 1
else
  keys = pi[0].keys
end

iter1 = pi[0].iterations
iter2 = pi[1].iterations

if iter1 != iter2
  $stderr.puts "perfcomp: scaling performance data: iterations of run 1 and run 2 differ: #{iter1}/#{iter2}"
end

if iter1 < iter2
  c1 = iter2 / iter1
  c2 = 1
else
  c1 = 1
  c2 = iter1 / iter2
end

printf "perf data file 1: #{files[0].path}\n"
printf "  requests=#{iter1}, options=#{pi[0].options}\n\n"
printf "perf data file 2: #{files[1].path}\n"
printf "  requests=#{iter2}, options=#{pi[1].options}\n\n"

if narrow
  printf "%-3s %9s %9s %7s %7s %8s %8s %6s\n",
         'page', 'c1 real', 'c2 real', 'c1 r/s', 'c2 r/s', 'c1 ms/r', 'c2 ms/r', 'c1/c2'
else
  printf "%-32s %9s %9s %7s %7s %8s %8s %6s\n",
         'page', 'c1 real', 'c2 real', 'c1 r/s', 'c2 r/s', 'c1 ms/r', 'c2 ms/r', 'c1/c2'
end

keys.each_with_index do |k, index|
  # average runtime
  t1 = pi[0].timings_mean(k) * c1
  t2 = pi[1].timings_mean(k) * c2
  urls1 = pi[0].requests_per_key
  urls2 = pi[1].requests_per_key

  # requests per second
  rps1 = iter1*urls1*c1/t1
  rps2 = iter2*urls2*c2/t2

  # milliseconds per request
  mspr1 = t1*1000/(iter1*urls1*c1)
  mspr2 = t2*1000/(iter2*urls2*c2)

  if narrow
    printf "%2d:  %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           (index+1), t1, t2, rps1, rps2, mspr1, mspr2, t1/t2
  else
    printf "%-32s %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           truncate(k), t1, t2, rps1, rps2, mspr1, mspr2, t1/t2
  end
end

total_requests_run1 = pi[0].request_count
total_requests_run2 = pi[1].request_count
total_time1 = pi[0].total_time_mean * c1
total_time2 = pi[1].total_time_mean * c2
total_rps1 = total_requests_run1 * c1 / total_time1
total_rps2 = total_requests_run2 * c2 / total_time2
total_mspr1 = total_time1 * 1000 / (total_requests_run1 * c1)
total_mspr2 = total_time2 * 1000 / (total_requests_run2 * c2)

if narrow
  printf "\n%4s %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           "all:", total_time1, total_time2,
                total_rps1, total_rps2, total_mspr1, total_mspr2,
                     total_time1/total_time2
else
  printf "\n%-32s %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           "all requests", total_time1, total_time2,
                total_rps1, total_rps2, total_mspr1, total_mspr2,
                     total_time1/total_time2
end

if pi[0].gc_stats? && pi[1].gc_stats?
  c1 = pi[0].gc_calls_mean
  t1 = pi[0].gc_time_mean
  c2 = pi[1].gc_calls_mean
  t2 = pi[1].gc_time_mean
  factor = (t1-t2==0) ? 1 : t1/t2

  if narrow
    printf "\n%-4s %9s %9s %7s %7s %8s %8s %6s\n",
           "GC:", "c1 real", "c2 real", "c1 #gc", "c2 #gc", "c1 gc%", "c2 gc%", "c1/c2"
    printf "%-4s %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           "", t1, t2, c1, c2, (t1/total_time1)*100, (t2/total_time2)*100, factor
  else
    printf "\n%-32s %9s %9s %7s %7s %8s %8s %6s\n",
           "garbage collection stats", "c1 real", "c2 real", "c1 #gc", "c2 #gc", "c1 gc%", "c2 gc%", "c1/c2"
    printf "%-32s %9.5f %9.5f %7.1f %7.1f %8.2f %8.2f %6.2f\n",
           "", t1, t2, c1, c2, (t1/total_time1)*100, (t2/total_time2)*100, factor
  end
end

if narrow and !skip_urls
  puts "\nurls:"
  keys.each_with_index do |k, index|
    printf "%2d: %s\n", (index+1) , k
  end
end

__END__

#    Copyright (C) 2005-2008  Stefan Kaes
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
