Makie.jl: Slow REPL together with Makie

Created on 15 Dec 2018  路  15Comments  路  Source: JuliaPlots/Makie.jl

I'm currently using Makie with quite elaborate scenes in high resolution. I've found that sometimes stdin/stdout in the REPL is very, very slow if there is a scene window open (like every character takes a fraction of a second to be output, which is frustrating for long Julia errors). Julia itself is still fast, just the REPL is slow.

Most helpful comment

The Julia REPL runs in a julia Task; GLMakie also runs the GUI in a Task (screen.rendertask). In current Julia these have to share the same CPU thread via cooperative multitasking.

So whether the REPL Task will get enough resources to feel responsive depends on how good the rendering backend is at sharing the CPU. At the moment this is done here for GLMakie: https://github.com/JuliaPlots/GLMakie.jl/blob/6ea449dd1bd7878831e7086a7f20afd9e16f5b30/src/rendering.jl#L11.

From the look of this, if you have a scene which isn't meeting the target framerate, the REPL task will be scheduled only once every frame. This could be due to CPU work (ie, scene preparation due to animation etc), and there's not a whole lot which can be done about that in current julia. Other than maybe adding a few more calls to yield() in strategically chosen locations.

Alternatively it could be due to CPU blocking while the GPU does work. Ideally we'd send all the work to the GPU and then release the CPU to do other things while we're waiting. OpenGL is generally asynchronous like this but there's certain things which force it to be synchronous, such as reading rendered frames back. For example when selecting objects by using glReadPixels here: https://github.com/JuliaPlots/GLMakie.jl/blob/6ea449dd1bd7878831e7086a7f20afd9e16f5b30/src/screen.jl#L293. It looks like Simon has been fairly careful to keep the GPU work async where possible, but it could be that you've hit an edge case. Can you give a stripped down example of the problem?

All 15 comments

The Julia REPL runs in a julia Task; GLMakie also runs the GUI in a Task (screen.rendertask). In current Julia these have to share the same CPU thread via cooperative multitasking.

So whether the REPL Task will get enough resources to feel responsive depends on how good the rendering backend is at sharing the CPU. At the moment this is done here for GLMakie: https://github.com/JuliaPlots/GLMakie.jl/blob/6ea449dd1bd7878831e7086a7f20afd9e16f5b30/src/rendering.jl#L11.

From the look of this, if you have a scene which isn't meeting the target framerate, the REPL task will be scheduled only once every frame. This could be due to CPU work (ie, scene preparation due to animation etc), and there's not a whole lot which can be done about that in current julia. Other than maybe adding a few more calls to yield() in strategically chosen locations.

Alternatively it could be due to CPU blocking while the GPU does work. Ideally we'd send all the work to the GPU and then release the CPU to do other things while we're waiting. OpenGL is generally asynchronous like this but there's certain things which force it to be synchronous, such as reading rendered frames back. For example when selecting objects by using glReadPixels here: https://github.com/JuliaPlots/GLMakie.jl/blob/6ea449dd1bd7878831e7086a7f20afd9e16f5b30/src/screen.jl#L293. It looks like Simon has been fairly careful to keep the GPU work async where possible, but it could be that you've hit an edge case. Can you give a stripped down example of the problem?

Can you give a stripped down example of the problem?

I think it usually happens after call to resize!() (try e.g. resize!(scene,(3000,3000))
My guess is that nobody else is using scenes of this size. But I need them as I want to use crops of the results for a publication, and they look kind of bad unless the scene is big enough.

Do you even need a renderloop then?

Probably not really. It's nice to see the results of what is rendered on the screen now and then, but it isn't a big issue if I have to save them somewhere and then inspect.

What would happen if you started julia with JULIA_NUM_THREADS=2? Just out of curiosity

Probably not really. It's nice to see the results of what is rendered on the screen now and then, but it isn't a big issue if I have to save them somewhere and then inspect.

It would be fairly simple to only render a frame on display, which should completely avoid this issue... need to figure out a nice API! Any recommendations are appreciated ;)

What would happen if you started julia with JULIA_NUM_THREADS=2? Just out of curiosity

Pretty sure that nothing will happen... How do you get the idea that something should happen?
Neither my code nor the REPL code is using threads - as a matter of fact, Julia still doesn't really support worker threads as of now, so it's almost impossible to improve the situation via threads right now :(

Dang. Just thought of it from @c42f's comment about processes sharing a thread, so I thought if you allowed Julia more threads it could split the processes.

@SimonDanisch

For an API, how about having something like a constructor "Scene(;renderloop=[true|false])". In the case that renderloop==true Makie could do what it currently does. In the case that renderloop==false, it would only render the scene once after calls that change the scene?

@natschil could you share an MWE? I just compiled the latest build of Makie, and I'd like to test it out.

I can't seem to reproduce it on my laptop at the moment, I'll try to reproduce it on a workstation where I've seen problems tomorrow.

I thought if you allowed Julia more threads it could split the processes

This is how things should work but julia's Task system is not multithreaded yet, and won't be until https://github.com/JuliaLang/julia/pull/22631 (or equivalent) is merged.

I have the same REPL slowness here even with fairly small, simple plots. Using Julia v1.5.0-rc2, AbstractPlotting v0.12.5, GLMakie v0.1.8, on a 2020 macbook pro, running this MWE plot takes 13 seconds for just printing rand(20,20) (instead of 0.02 seconds when I'm not plotting stuff)... Am I doing something wrong?

using AbstractPlotting
using AbstractPlotting.MakieLayout
# Some data
x, y = 0:0.01:2蟺, 0:0.1:10
f(x,y) = (cos(x) + y > 9) ? NaN : cos(x) * sin(y)
data = [f(x,y) for x in x, y in y] ;
# A function to plot
function myplot(x, y, data)
    scene, layout = layoutscene(10, resolution = (300, 300))
    ax = layout[1,1] = LAxis(scene)
    heatmap!(ax, x, y, data)
    ylims!(ax, (10,0))
    return scene
end
# GLMakie plot
using GLMakie; GLMakie.activate!()
display(myplot(x, y, data))
# time to print at REPL:
@time println(rand(20,20)) # takes 13.4 seconds

This issue has gotten worse since we started using vsync. You can turn that off by setting GLMakie.WINDOW_CONFIG.vsync[] = false.

This issue has gotten worse since we started using vsync. You can turn that off by setting GLMakie.WINDOW_CONFIG.vsync[] = false.

~This does not help for me. I just tried (added GLMakie.WINDOW_CONFIG.vsync[] = false just before the @time println(rand(20,20))) and it still takes 13 seconds to print that.~


EDIT: This works! The time-to-print has gone back to normal! Maybe make revert this change? (Thanks @ffreyer, you were correct, I had not closed the window!)

You have to close the window for this to take effect

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mohamed82008 picture mohamed82008  路  6Comments

grahamas picture grahamas  路  3Comments

DoktorMike picture DoktorMike  路  6Comments

EricForgy picture EricForgy  路  5Comments

SebastianM-C picture SebastianM-C  路  3Comments