Open paulmelis opened 3 months ago
This could potentially be sped up by adding some precompile statements, I'll give that a look. The allocations when using CairoMakie are expected, because it internally translates the surface grid to a triangle mesh, which has 2*nx*ny
faces.
~Display is somehow taking 100 seconds for me on first run 😅 which is definitely unexpected...~
Edit: it turns out that I mixed up lons and lats when making this example work without the JLD file (which I didn't see in the issue), but that did expose an interesting bug in CairoMakie so I'll call it fair :D
Here's a more minimal MWE, and the timings broadly agree with what you show:
using GeoMakie
using CairoMakie
#using GLMakie
function go()
lons = LinRange(-180, 180, 390)
lats = LinRange(-90, 90, 390)
values = rand(length(lons), length(lats))
t0 = time()
println("Figure()")
@time fig = Figure()
println("GeoAxis()")
@time ax = GeoAxis(fig[1,1],
source="+proj=longlat +datum=WGS84",
dest="+proj=lcc +lon_0=5 +lat_1=50 +lat_2=55")
println("surface!()")
@time surf = surface!(ax, lons, lats, values; shading=NoShading)
println("Colorbar()")
@time Colorbar(fig[2,1], surf; ticklabelsize=10, tickwidth=1, vertical=false)
println("display()")
@time display(fig)
t1 = time()
println("time-to-plot $((t1-t0)*1000)ms")
end
go()
Using TimerOutputs (manually inserted into Makie) gets me the result below, which clearly indicates that defining and drawing the mesh to Cairo takes the bulk of time here. We could get this down a bit maybe by implementing a mesh renderer in CairoMakie but that would take a while.
──────────────────────────────────────────────────────────────────────────────────────────
Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 2.86s / 57.6% 302MiB / 89.6%
Section ncalls time %tot avg alloc %tot avg
──────────────────────────────────────────────────────────────────────────────────────────
surface 1 1.64s 99.5% 1.64s 269MiB 99.4% 269MiB
draw_mesh3D 1 1.63s 99.0% 1.63s 249MiB 91.9% 249MiB
draw_mesh3D_decomposed 1 1.40s 85.1% 1.40s 153MiB 56.6% 153MiB
draw_pattern 1 1.31s 79.4% 1.31s 39.2MiB 14.4% 39.2MiB
Cairo drawing 302k 1.21s 73.6% 4.02μs 4.61MiB 1.7% 16.0B
apply transform 1 21.7ms 1.3% 21.7ms 2.32MiB 0.9% 2.32MiB
camera to screen space 1 590μs 0.0% 590μs 1.74MiB 0.6% 1.74MiB
per face colors 1 228ms 13.8% 228ms 90.5MiB 33.4% 90.5MiB
mesh attribute extraction 1 1.15ms 0.1% 1.15ms 5.20MiB 1.9% 5.20MiB
Surface2Mesh 1 8.31ms 0.5% 8.31ms 20.3MiB 7.5% 20.3MiB
color extraction 1 12.6μs 0.0% 12.6μs 224B 0.0% 224B
faceculling 1 7.33μs 0.0% 7.33μs 576B 0.0% 576B
lines 3 6.64ms 0.4% 2.21ms 1.49MiB 0.5% 508KiB
text 6 513μs 0.0% 85.5μs 57.8KiB 0.0% 9.63KiB
image 1 252μs 0.0% 252μs 6.67KiB 0.0% 6.67KiB
linesegments 7 89.5μs 0.0% 12.8μs 8.09KiB 0.0% 1.16KiB
──────────────────────────────────────────────────────────────────────────────────────────
The allocations when using CairoMakie are expected, because it internally translates the surface grid to a triangle mesh, which has
2*nx*ny
faces.
Why draw as a triangle mesh, and not quads? That would potentially half the number of draw calls (and I'm sure Cairo can support it)
Quads are not well supported supported by vector graphics (Cairo usually rasterizes them in many formats, and the file sizes get pretty insane even if not rasterized), and the majority of time is spent preparing the Cairo pattern anyway.
I had tried this before but the tradeoff simply isn't worth it - the better option is to implement a pure Julia mesh rasterizer (not actually too hard) and then rasterize the mesh to an image, and emit the image.
Quads are not well supported supported by vector graphics (Cairo usually rasterizes them in many formats, and the file sizes get pretty insane even if not rasterized)
I don't know all the details of what frequently gets output from Cairo when used from Julia (I only use it to rasterize vector graphics directly from C/C++, not to save to svg for example), but to which formats does it rasterize?
and the majority of time is spent preparing the Cairo pattern anyway.
Is that in https://github.com/MakieOrg/Makie.jl/blob/77f2cfdb15b85374f449c5cdc3ad3c108cf858e2/CairoMakie/src/primitives.jl#L975? Can't you create the pattern once and then reuse it for all triangles?
output from Cairo when used from Julia
Usually SVG (quads not supported, so the whole SVG gets rasterized internally), PDF (quads supported but filesize >100mb vs 20mb with triangles), or PNG (long rasterization time).
Can't you create the pattern once and then reuse it for all triangles
Not to my knowledge, unless Cairo has a nice API for that? We are changing the points and the colors at each pattern, so it's a nontrivial reconstruction.
cf https://github.com/MakieOrg/Makie.jl/issues/4112 - this may be the reason why this issue exists.
First run from REPL (10.5s to plot):
Second run, same REPL session (1.95s):
Even in the second run the
display()
call seems to have lots of allocations for such a small dataset. Is this to be expected, and particular to GeoMakie?