require 'benchmark'
require 'thread'

N = Integer(ARGV.shift || 1000)

puts "RUBY_DESCRIPTION: #{RUBY_DESCRIPTION}"
puts "Queue#close: #{Queue.instance_methods.include?(:close) ? 'yes' : 'no'}"

GC.disable

# Adapted from http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/391324

Benchmark.bm(50) do |bm|
  bm.report '01 producer 01 consumer' do
    q = SizedQueue.new 1000
    th = Thread.new do
      n = 0
      loop do
        item = q.pop
        raise StopIteration unless item
        n += 1
      end
    end

    N.times do
       100.times do |item|
         q.push item
       end
    end

    if q.respond_to? :close
      q.close StopIteration
    else
      q.push nil
    end

    th.join
  end

  bm.report '01 producer 02 consumer' do
    q = SizedQueue.new 1000
    cthreads = 2.times.map do |i|
      Thread.new do
        n = 0
        loop do
          item = q.pop
          raise StopIteration unless item
          n += 1
        end
      end
    end

    N.times do
       100.times do |item|
         q.push item
       end
    end

    if q.respond_to? :close
      q.close StopIteration
    else
      cthreads.each{ q.push nil }
    end

    cthreads.each &:join
  end

  bm.report '01 producer 99 consumer' do
    q = SizedQueue.new 1000
    cthreads = 99.times.map do |i|
      Thread.new do
        n = 0
        loop do
          item = q.pop
          raise StopIteration unless item
          n += 1
        end
      end
    end

    N.times do
       100.times do |item|
         q.push item
       end
    end

    if q.respond_to? :close
      q.close StopIteration
    else
      cthreads.each{ q.push nil }
    end

    cthreads.each &:join
  end

  bm.report '02 producer 01 consumer' do
    q = SizedQueue.new 1000
    cthreads = 1.times.map do |i|
      Thread.new do
        n = 0
        loop do
          item = q.pop
          raise StopIteration unless item
          n += 1
        end
      end
    end

    count_pthreads = 2
    pthreads = count_pthreads.times.map do |i|
      Thread.new do
        (N / count_pthreads).times do
          100.times do |item|
            q.push item
          end
        end
      end
    end

    pthreads.each &:join

    if q.respond_to? :close
      q.close StopIteration
    else
      cthreads.each{ q.push nil }
    end

    cthreads.each &:join
  end

  bm.report '99 producer 01 consumer' do
    q = SizedQueue.new 1000
    cthreads = 1.times.map do |i|
      Thread.new do
        n = 0
        loop do
          item = q.pop
          raise StopIteration unless item
          n += 1
        end
      end
    end

    count_pthreads = 99
    pthreads = count_pthreads.times.map do |i|
      Thread.new do
        (N / count_pthreads).times do
          100.times do |item|
            q.push item
          end
        end
      end
    end

    pthreads.each &:join

    if q.respond_to? :close
      q.close StopIteration
    else
      cthreads.each{ q.push nil }
    end

    cthreads.each &:join
  end
end
