Roadmap for a faster time-to-first-plot?

I think the problem is not related to GR directly. It’s probably another package dependency (for FFTW.jl). On macOS, the latter might be provided by Homebrew - did you try to rebuild it?

Thanks for the tip – GR and all associated packages (including FFTW) work fine on my system outside of PackageCompiler. I only get these image not found errors from PackageCompiler attempts. Just to check though, I just did ] build FFTW and then repeated the same experiment above, and got the same error.

While I was horking around Julia GUI’s and things I found something. I’m of course very interested in the ideas of interactive plots using native Julia and stuff like that so I ended up in Plots.jl. When I was groking the GR backend for how plots get rendered, I realized something a little funny. It looks like every display has a read and write step via something called GKS? Is that correct? I’m no wizard, but typically reading and writing is pretty slow compared to in memory. I don’t foresee this being a huge deal in time-to-first plot but, it could be if the plots were large enough. Could also introduce latency in animations.

https://github.com/JuliaPlots/Plots.jl/blob/f2e98acc65c417fce2b8338a3300c9a790f40008/src/backends/gr.jl#L1408

Is there a direct way to convert Plots to a graphical context without I/O? Or does this even matter according to benchmarks?

1 Like

For PDF as shown in the above example it would not make much sense. In Plots, however, the GR.emergencyclosegks() might cause some overhead within GR, which should be avoided in a future version.

The @time macro does not seem to tell the full truth, at least for me. Doing the timing actually gives me 7 seconds.

julia> @time (using Plots; gr(); plot([1,2,3], [4,5,6]))
  7.053711 seconds (15.98 M allocations: 845.897 MiB, 3.60% gc time)

However, at the time the output (7s) is shown, the plot is not yet displayed. It will (measured manually) take an additional ~5-6 seconds for the plot to pop up, i.e. in total it’s 13 seconds not 7. A second plot will however appear nearly instantly. Is this a known behavior and if so, where do these additional 5-6 seconds come from?

What version of Julia are you running (julia> versioninfo())?
Have you updated your packages (julia> using Pkg; Pkg.update())?

They come from calling display on the Plot object, which is implicitly called when returning the plot to the REPL. Call display(plot(...)) explicitly to time the full operation.

5 Likes

Thank’s for the quick response, this is really good to know, when doing some measurements!

Hmm. I get much better results with the “package compiled” Plots version:

% julia -J /usr/local/lib/julia/packages/PackageCompiler/CJQcs/sysimg/sys
julia> @time using Plots; gr(); display(plot(randn(10)))
  0.000909 seconds (1.24 k allocations: 61.531 KiB)

julia> versioninfo()
Julia Version 1.3.1
Commit 2d5741174c (2019-12-30 21:36 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin18.6.0)
  CPU: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)
Environment:
  JULIA_DEPOT_PATH = /usr/local/lib/julia:
  JULIA_HISTORY = /Users/jheinen/.julia/logs/repl_history.jl

(v1.3) pkg> st Plots
    Status `/usr/local/lib/julia/environments/v1.3/Project.toml`
  [53c48c17] FixedPointNumbers v0.6.1
  [28b8d3ca] GR v0.46.0 #master (https://github.com/jheinen/GR.jl.git)
  [77ba4419] NaNMath v0.3.3
  [ccf2f8ad] PlotThemes v1.0.1
  [995b91a9] PlotUtils v0.6.2 #master (https://github.com/JuliaPlots/PlotUtils.jl.git)
  [91a5bcdd] Plots v0.28.5 #master (https://github.com/JuliaPlots/Plots.jl.git)
  [3cdcf5f2] RecipesBase v0.7.0 #master (https://github.com/JuliaPlots/RecipesBase.jl.git)
  [992d4aef] Showoff v0.3.1 #master (https://github.com/JuliaGraphics/Showoff.jl.git)
  [2913bbd2] StatsBase v0.32.0

I use snoop-Plots.jl as a workload for Plots.jl.

5 Likes

If you have trouble with the above workload script (on macOS), you probably have to comment out the StatsPlots test in the end. See note from @ianfiske

Did anything come out of this yet? Any tooling for more precisely identifying why inference/compile-time is slow?

Lots of things. We noticed the Plots.jl time actually goes to around 5 seconds with -O0, so we were underestimating the LLVM time and that means there’s more to do there. It’s somewhat hard to benchmark because the issues now that precompile files have been enhanced are mostly about method invalidation: someone defines a lower dispatch that “infects” that suddenly causes a lot less precompile to be reused. A big issue in CSV.jl was noted to be due to that, and that’s really where all of the profiling seems to lead. Some of that could be fixed by moving some more of these basic dispatches to Base.

10 Likes

Sounds great! Where could I follow the progress or discussions? I didn’t find anything recent.

Come to Boston :slight_smile:! A lot of this is just developing daily. and things get online as they get more concrete.

I’d love to but there are ~6000km and a big ocean in the way. I guess I’ll just have to be patient then :smile:

6 Likes

It’s such a long post! I lost the point. Is there a roadmap?

We’re mostly already there

2 Likes

For the record, @jzr mentioned a while back in another post the SandDance extension for VSCode. If Julia code writes the data to be plotted to disk as a CSV file, a right click to view it in SandDance is instantaneous. Yes, the number of plot types is limited, but powerful for some applications.

using DelimitedFiles
x = 0:0.1:2π
y = sin.(x)
open("delim_file_4_sanddance.csv", "w") do io
    writedlm(io, ["X" "Y"], ',')
    writedlm(io, [x y], ',')
end

It would be handy to have a sandance function available: sanddance.view(filename)

6 Likes

I started a Julia wrapper at some point: https://github.com/queryverse/SandDance.jl. But it is not well maintained, not sure whether it even works at all right now…

6 Likes

@davidanthoff, SandDance.jl works pretty well (Win10, Julia 1.7). The time to first plot seems to be < 2 s for small datasets and about 4-5 s for ~10K points. Thank you.

# pkg> add  https://github.com/queryverse/SandDance.jl
using SandDance, DataFrames
f(x,y) = exp(-x^2*y^2)*sin(x*y)
n = 100
x = y = LinRange(-π, π, n)
xx = x' .* ones(n)
yy = ones(n)' .* y
zz = f.(xx,yy)
data2d = DataFrame(x=xx[:], y=yy[:], z=zz[:])
SandDanceWindow(data2d)

10 Likes