mandelbrot Ruby yjit #6 program
source code
# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
#
# Contributed by Aaron Tavistock
require 'thread'
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
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 self.render(size)
m = Mandel.new(size)
m.process
print "#{m.header}\n#{m.output.join}"
end
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 # Using a thread pool to manage processes
@size.times do |row|
workers.schedule(row) do |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
@output[y] = read.read
end
end
workers.shutdown
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(0b0, 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
return 0b0 if zrzr + zizi > 4.0
count -= 1
end
0b1
end
end
Mandel.render(ARGV.shift)
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 19:50:38 GMT
COMMAND LINE:
/opt/src/ruby-3.3.5/bin/ruby --yjit -W0 mandelbrot.ruby-6.ruby 4000
PROGRAM FAILED
(BINARY) PROGRAM OUTPUT NOT SHOWN
#<Thread:0x00007f9d5c81c698 mandelbrot.ruby-6.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-6.ruby:71:in `pipe': Too many open files (Errno::EMFILE)
from mandelbrot.ruby-6.ruby:71:in `block (2 levels) in process'
from mandelbrot.ruby-6.ruby:29:in `block (3 levels) in initialize'
from mandelbrot.ruby-6.ruby:26:in `catch'
from mandelbrot.ruby-6.ruby:26:in `block (2 levels) in initialize'
#<Thread:0x00007f9d5c81cb20 mandelbrot.ruby-6.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-6.ruby:71:in `pipe': Too many open files (Errno::EMFILE)
from mandelbrot.ruby-6.ruby:71:in `block (2 levels) in process'
from mandelbrot.ruby-6.ruby:29:in `block (3 levels) in initialize'
from mandelbrot.ruby-6.ruby:26:in `catch'
from mandelbrot.ruby-6.ruby:26:in `block (2 levels) in initialize'
#<Thread:0x00007f9d5c81cc88 mandelbrot.ruby-6.ruby:24 run> terminated with exception (report_on_exception is true):
mandelbrot.ruby-6.ruby:71:in `pipe': Too many open files (Errno::EMFILE)
from mandelbrot.ruby-6.ruby:71:in `block (2 levels) in process'
from mandelbrot.ruby-6.ruby:29:in `block (3 levels) in initialize'
from mandelbrot.ruby-6.ruby:26:in `catch'
from mandelbrot.ruby-6.ruby:26:in `block (2 levels) in initialize'
mandelbrot.ruby-6.ruby:71:in `pipe': Too many open files (Errno::EMFILE)
from mandelbrot.ruby-6.ruby:71:in `block (2 levels) in process'
from mandelbrot.ruby-6.ruby:29:in `block (3 levels) in initialize'
from mandelbrot.ruby-6.ruby:26:in `catch'
from mandelbrot.ruby-6.ruby:26:in `block (2 levels) in initialize'