Can't parallelize code in Julia (@distributed)

48 Views Asked by At

I'm writing some code in Julia so that I can zoom in on a Mandelbrot set. Performance is taking a hit, so I'm trying to parallelize it. This is what I got:

using Interact, DynamicalSystems
using LinearAlgebra
using Images, ImageView
using ImageTransformations
using CairoMakie, Colors, ColorSchemes
using FileIO
using Cairo
using FixedPointNumbers
using MiniFB
using Plots
using Distributed

@everywhere begin
    using Pkg; Pkg.activate(@__DIR__)
    Pkg.instantiate(); Pkg.precompile()
  end

addprocs(8)

@everywhere begin
    function mandelbrot(xmin, xmax, ymin, ymax, width, height, max_iter, threshold,exponent)
        img = zeros(RGB{Float64}, height, width)
        #C(g::ColorGradient) = RGB[g[zz] for zz=LinRange(0,1,30)]
        #gg = :inferno
        #gg = cgrad(gg)
        
        @distributed for j in UnitRange(1:height)
            for i in 1:width
                x = range(xmin, stop=xmax, length=width)
                x = x[i]
                y = range(ymin, stop = ymax, length = height)
                y = y[j]
                c = x + y * im
                z = c
                
                for iter in 1:max_iter
                    if abs(z)<= threshold
                        img[j,i] = RGB(0,0,0)
                    elseif abs(z) > threshold
                        idx = iter / max_iter
                        img[j,i] = RGB(j/height,i/width,idx)
                        #img[j, i] = RGB(gg[idx].r, gg[idx].g, gg[idx].b)
                        break
                    end
                    az = real(z)
                    bz = imag(z)
                    z = (az+bz)*(az-bz) + (az+az)*bz*im + c
                    #z = (z^4+im*z^2+1)/(z^2+1) + c
                end
            end
        end

        return img
    end
end

function convert_to_n0f8(rgb::RGB{Float64})
    r = clamp01(rgb.r)
    g = clamp01(rgb.g)
    b = clamp01(rgb.b)
    return RGB{N0f8}(r, g, b)
end

function range_mod(val_min, val_max, length)
    return range(val_min, val_max, length)
end

function convert_matrix_to_n0f8(matrix::Matrix{RGB{Float64}})
    return [convert_to_n0f8(rgb) for rgb in matrix]
end

function coords_calc(mouse_x, mouse_y, xrange, yrange, factor)
    x_click = xrange[mouse_x]
    y_click = yrange[mouse_y]

    xcen, ycen = x_click, y_click
    xmin, xmax = xcen-factor*(xrange[end]-xrange[1]), xcen+factor*(xrange[end]-xrange[1])
    ymin, ymax = ycen-factor*(yrange[end]-yrange[1]), ycen+factor*(yrange[end]-yrange[1])

    return xcen, ycen, xmin, xmax, ymin, ymax
end

max_iter = 200
xmin, xmax = -2., 2.
ymin, ymax = -2., 2.
exponent = 2
threshold = 2

# Set the size of the window
global const WIDTHh = 800
global const HEIGHTh = 600

global ni = 1
global num_images = 1

function onclick(window, button, mod, isPressed)::Cvoid
    global xmin, xmax, ymin, ymax, images, ni
    if Bool(isPressed)

        x_mouse = mfb_get_mouse_x(window)
        y_mouse = mfb_get_mouse_y(window)

        x_range = range(xmin, stop = xmax, length = WIDTHh)
        y_range = range(ymin, stop = ymax, length = HEIGHTh)

        _, _, xmin, xmax, ymin, ymax = coords_calc(x_mouse, y_mouse, x_range, y_range, 0.1)
        push!(images,mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, threshold, exponent))
        #images = vcat(images,mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, 2, 2, 0))
        ni += 1
    end
    return nothing
end

function populate_buffer!(buffer, img)
    global WIDTHh, HEIGHTh
    buffer[:] = zeros(UInt32, HEIGHTh*WIDTHh)
    h, w = size(img)
    ratio = min(1, HEIGHTh/h, WIDTHh/w)
    nimg = imresize(img, ratio=ratio)
    nh, nw = size(nimg)
    oh = (HEIGHTh-nh) ÷ 2
    ow = (WIDTHh-nw) ÷ 2
    for i in 1:nh
        for j in 1:nw
            buffer[(oh+i-1)*WIDTHh + ow+j] = mfb_rgb(nimg[i,j])
        end
    end
end

function imageview(dir::String=".")
    global xmin, xmax, ymin, ymax, images
    images = Vector{Matrix{RGB{Float64}}}()
    img2 =  mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, threshold, exponent)
    push!(images,convert_matrix_to_n0f8(img2))
    num_images = length(images)
  
    buffer = zeros(UInt32, HEIGHTh*WIDTHh)
    mfb_set_target_fps(2)
    window = mfb_open_ex("Image Viewer", WIDTHh, HEIGHTh, MiniFB.WF_RESIZABLE);
    mfb_set_mouse_button_callback(window, onclick);
    old_ni=0
    while mfb_wait_sync(window)
        if ni != old_ni
            populate_buffer!(buffer, images[ni])
            old_ni = ni
        end
        state = mfb_update(window, buffer);
        if state != MiniFB.STATE_OK
            break;
        end
    end
    mfb_close(window)
end

# Finally, call the main method to display the application
imageview(joinpath(dirname(pathof(MiniFB)),"..", "example"))

But what happens is that, if I run this code as it is, it doesn't run the @distributed loop. It returns a black image (corresponding to the mandelbrot() function without the loop). What can I do to fix this?

0

There are 0 best solutions below