{ "cells": [ { "cell_type": "code", "execution_count": 9, "id": "d959a605", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "juliaSetPixel" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"\n", "Computes a julia set pixel.\n", "\"\"\"\n", "function juliaSetPixel(z0, c)\n", " z = z0\n", " niter = 255\n", " for i in 1:niter\n", " abs2(z)> 4.0 && return (i - 1)%UInt8\n", " z = z*z + c\n", " end\n", " return niter%UInt8\n", "end\n", "\n", "\"\"\"\n", "Computes a column (`j`) of the julia set image.\n", "The result is written into the corresponding column of `pic`.\n", "\"\"\"\n", "function calcColumn!(pic, c, n, j)\n", " x = -2.0 + (j-1)*4.0/(n-1)\n", " for i in 1:n\n", " y = -2.0 + (i-1)*4.0/(n-1)\n", " @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n", " end\n", " nothing\n", "end\n", "\n", "\"\"\"\n", "Sequential column-by-column construction of the julia set image\n", "\"\"\"\n", "function juliaSetCalc!(pic, c, n)\n", " for j in 1:n\n", " calcColumn!(pic, c, n, j)\n", " end\n", " nothing\n", "end\n", "\n", "\"\"\"\n", "Compute the julia set image using the method `method`.\n", "\"\"\"\n", "function juliaSet(method = juliaSetCalc!, extra...)\n", " c = -0.79 + 0.15*im\n", " n = 1000\n", " pic = Array{UInt8,2}(undef,n,n)\n", " method(pic, c, n, extra...)\n", " return pic\n", "end" ] }, { "cell_type": "code", "execution_count": 19, "id": "660d8797", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Plots\n", "\n", "frac = juliaSet()\n", "plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))" ] }, { "cell_type": "code", "execution_count": 8, "id": "d2a74154", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 58.445 ms (2 allocations: 976.70 KiB)\n" ] } ], "source": [ "using BenchmarkTools\n", "@btime juliaSet();" ] }, { "cell_type": "markdown", "id": "645fe937", "metadata": {}, "source": [ "## Multithreading: `@threads`" ] }, { "cell_type": "code", "execution_count": 82, "id": "737bd435", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "juliaSetCalcThread! (generic function with 1 method)" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import Base.Threads: @threads\n", "\n", "function juliaSetCalcThread!(pic, c, n)\n", " @threads for j in 1:n\n", " calcColumn!(pic, c, n, j)\n", " end\n", " return nothing\n", "end" ] }, { "cell_type": "code", "execution_count": 83, "id": "aa45672d", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frac = juliaSet(juliaSetCalcThread!)\n", "plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))" ] }, { "cell_type": "code", "execution_count": 22, "id": "0de85d17", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 17.758 ms (35 allocations: 979.17 KiB)\n" ] } ], "source": [ "@btime juliaSet(juliaSetCalcThread!);" ] }, { "cell_type": "code", "execution_count": 84, "id": "f7b4f188", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "juliaSetPixel (generic function with 1 method)" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Turon on debugging :D\n", "import Base.Threads: nthreads, threadid\n", "\n", "function calcColumn!(pic, c, n, j)\n", " x = -2.0 + (j-1)*4.0/(n-1)\n", " cols[j] = threadid()\n", " for i in 1:n\n", " y = -2.0 + (i-1)*4.0/(n-1)\n", " @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n", " end\n", " nothing\n", "end\n", "\n", "function juliaSetPixel(z0, c)\n", " z = z0\n", " niter = 255\n", " for i in 1:niter\n", " niters[threadid()] += 1\n", " abs2(z)> 4.0 && return (i - 1)%UInt8\n", " z = z*z + c\n", " end\n", " return niter%UInt8\n", "end" ] }, { "cell_type": "code", "execution_count": 85, "id": "fd485770", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "niters = zeros(nthreads())\n", "cols = zeros(1000)\n", "juliaSet(juliaSetCalcThread!)\n", "bar(niters, xlab=\"threadid\", ylab=\"# iterations\", legend=false)" ] }, { "cell_type": "code", "execution_count": 156, "id": "d6d7cf43", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ "heatmap([c for i in 1:length(cols), c in cols])" ] }, { "cell_type": "markdown", "id": "43623524", "metadata": {}, "source": [ "## Multithreading: `@spawn`" ] }, { "cell_type": "code", "execution_count": 77, "id": "c50f0e5f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "juliaSetCalcSpawn! (generic function with 1 method)" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import Base.Threads: @spawn\n", "\n", "function juliaSetCalcSpawn!(pic, c, n)\n", " @sync for j in 1:n\n", " @spawn calcColumn!(pic, c, n, j)\n", " end\n", " return nothing\n", "end" ] }, { "cell_type": "code", "execution_count": 162, "id": "e69b966f", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 162, "metadata": {}, "output_type": "execute_result" } ], "source": [ "niters = zeros(nthreads())\n", "cols = zeros(1000)\n", "juliaSet(juliaSetCalcSpawn!)\n", "bar(niters, xlab=\"threadid\", ylab=\"# iterations\", legend=false)" ] }, { "cell_type": "code", "execution_count": 163, "id": "0f01a4fc", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "heatmap([c for i in 1:length(cols), c in cols])" ] }, { "cell_type": "code", "execution_count": 164, "id": "8f96d09a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "juliaSetPixel (generic function with 1 method)" ] }, "execution_count": 164, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Turn off debugging :D\n", "function calcColumn!(pic, c, n, j)\n", " x = -2.0 + (j-1)*4.0/(n-1)\n", " for i in 1:n\n", " y = -2.0 + (i-1)*4.0/(n-1)\n", " @inbounds pic[i,j] = juliaSetPixel(x+im*y, c)\n", " end\n", " nothing\n", "end\n", "\n", "function juliaSetPixel(z0, c)\n", " z = z0\n", " niter = 255\n", " for i in 1:niter\n", " abs2(z)> 4.0 && return (i - 1)%UInt8\n", " z = z*z + c\n", " end\n", " return niter%UInt8\n", "end" ] }, { "cell_type": "code", "execution_count": 165, "id": "92c178d4", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "frac = juliaSet(juliaSetCalcSpawn!)\n", "plot(heatmap(1:size(frac,1),1:size(frac,2), frac, color=:Spectral))" ] }, { "cell_type": "code", "execution_count": 73, "id": "5a63d3b1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 10.137 ms (6022 allocations: 1.38 MiB)\n" ] } ], "source": [ "@btime juliaSet(juliaSetCalcSpawn!);" ] }, { "cell_type": "markdown", "id": "d2f699a2", "metadata": {}, "source": [ "Based on http://www.cs.unb.ca/~aubanel/JuliaMultithreadingNotes.html." ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.6.1", "language": "julia", "name": "julia-1.6" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.6.1" } }, "nbformat": 4, "nbformat_minor": 5 }