The Computer Language
24.11 Benchmarks Game

mandelbrot Ruby yjit #7 program

source code

# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
#
# Contributed by Aaron Tavistock

WORKER_COUNT = begin
  cpu_count = if File.readable?('/proc/cpuinfo') # Linux
    %x(cat /proc/cpuinfo | grep -c processor).chomp.to_i
  elsif File.executable?('/usr/sbin/sysctl')  #OS/X
    %x(/usr/sbin/sysctl -n hw.ncpu).chomp.to_i
  else
    1
  end
  [(cpu_count * 2.0).to_i, 2].max
rescue
  2
end

class WorkerPool

  def initialize
    @work = Queue.new
    @pool = Array.new(WORKER_COUNT) do |i|
      Thread.new do
        Thread.current[:id] = i
        catch(:exit) do
          while(true) do
            work, args = @work.pop
            work.call(*args)
          end
        end
      end
    end
  end

  def schedule(*args, &block)
    @work << [block, args]
  end

  def shutdown
    @pool.size.times do
      schedule { throw :exit }
    end
    @pool.each do |t|
      t.join
    end
  end

end

class Mandel

  attr_reader :output

  def initialize(size)
    @size = size.to_i
    @output = Array.new(@size)
    @two_over_size = 2.0 / @size.to_f
  end

  def process
    workers = WorkerPool.new
    @size.times do |row|
      workers.schedule(row) do |y|
        @output[y] = process_row(y)
      end
    end
    workers.shutdown
  end

  def process_row(y)
    ci = (@two_over_size * y.to_f) - 1.0
    render_row(ci)
  end

  def forking_process_row(y)
    read, write = IO.pipe
    Process.fork do
      read.close
      ci = (@two_over_size * y.to_f) - 1.0
      write.print( render_row(ci) )
    end
    Process.wait
    write.close
    read.read
  end

  if RUBY_PLATFORM != 'java'
    alias_method :original_process_row, :process_row
    alias_method :process_row, :forking_process_row
  end

  def header
    "P4\n#{@size} #{@size}"
  end

  private

  def render_row(ci)
    row_bits = Array.new(@size) do |col|
      cr = (@two_over_size * col.to_f) - 1.5
      get_bit(cr, ci)
    end

    row = ''
    row_bits.each_slice(8) do |byte|
      if byte.size < 8
        byte = byte.fill(0, byte.size, 8 - byte.size)
      end
      row << byte.join.to_i(2).chr
    end
    row
  end

  def get_bit(cr, ci)
    zrzr = 0.0
    zizi = 0.0
    zrzi = 0.0

    count = 50
    while count > 0

      zr = zrzr - zizi + cr
      zi = 2.0 * zrzi + ci

      zrzr = zr * zr
      zizi = zi * zi
      zrzi = zr * zi

      if zrzr + zizi > 4.0
        return 0b0
      end

      count -= 1
    end

    0b1
  end

end

size = ARGV.shift || 1000
m = Mandel.new(size)
m.process
print "#{m.header}\n#{m.output.join}"
    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
ruby 3.3.5
(2024-09-03
revision ef084cc8f4)
+YJIT [x86_64-linux]


 Wed, 04 Sep 2024 20:22:22 GMT

COMMAND LINE:
 /opt/src/ruby-3.3.5/bin/ruby --yjit -W0 mandelbrot.ruby-7.ruby 4000

PROGRAM FAILED 


(BINARY) PROGRAM OUTPUT NOT SHOWN

#<Thread:0x00007c327c35d600 mandelbrot.ruby-7.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-7.ruby:77:in `pipe': Too many open files (Errno::EMFILE)
	from mandelbrot.ruby-7.ruby:77:in `forking_process_row'
	from mandelbrot.ruby-7.ruby:65:in `block (2 levels) in process'
	from mandelbrot.ruby-7.ruby:29:in `block (3 levels) in initialize'
	from mandelbrot.ruby-7.ruby:26:in `catch'
	from mandelbrot.ruby-7.ruby:26:in `block (2 levels) in initialize'
#<Thread:0x00007c327c35db50 mandelbrot.ruby-7.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-7.ruby:77:in `pipe': Too many open files (Errno::EMFILE)
	from mandelbrot.ruby-7.ruby:77:in `forking_process_row'
	from mandelbrot.ruby-7.ruby:65:in `block (2 levels) in process'
	from mandelbrot.ruby-7.ruby:29:in `block (3 levels) in initialize'
	from mandelbrot.ruby-7.ruby:26:in `catch'
	from mandelbrot.ruby-7.ruby:26:in `block (2 levels) in initialize'
#<Thread:0x00007c327c35dc90 mandelbrot.ruby-7.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-7.ruby:77:in `pipe': Too many open files (Errno::EMFILE)
	from mandelbrot.ruby-7.ruby:77:in `forking_process_row'
	from mandelbrot.ruby-7.ruby:65:in `block (2 levels) in process'
	from mandelbrot.ruby-7.ruby:29:in `block (3 levels) in initialize'
	from mandelbrot.ruby-7.ruby:26:in `catch'
	from mandelbrot.ruby-7.ruby:26:in `block (2 levels) in initialize'
mandelbrot.ruby-7.ruby:77:in `pipe': Too many open files (Errno::EMFILE)
	from mandelbrot.ruby-7.ruby:77:in `forking_process_row'
	from mandelbrot.ruby-7.ruby:65:in `block (2 levels) in process'
	from mandelbrot.ruby-7.ruby:29:in `block (3 levels) in initialize'
	from mandelbrot.ruby-7.ruby:26:in `catch'
	from mandelbrot.ruby-7.ruby:26:in `block (2 levels) in initialize'