dcjones/Gadfly.jl — pull request #346 by timholy (2014-06-30 16:46:33+00:00)
Title: WIP: first batch of performance improvements for Gadfly

Given the recompilation time for Gadfly/Compose, it proved to be easier to [modify julia to report the line number on which allocations occur](https://github.com/JuliaLang/julia/pull/7464) than it was to rely on the profiler :smile:. (The problem with the profiler/ProfileView is that it highlights garbage collection, but the real problem is allocation, and sometimes garbage collection occurs on a later line that's not contributing to the problem.)

Unsurprisingly, the big performance problem for Gadfly proves to be memory allocation & type stability. This is to be expected, because you have to deal with a whole zoo of types people want to throw at you. So you have a tough problem on your hands. The key point is that type-instability is mostly a problem in those parts of your algorithms that are `O(N)` where `N` is the number of data points. So whenever you iterate over the data points, use a function boundary to allow that iteration to be type-stable (you'll see several examples of that trick in these patches).

For the following test script,
```
import Gadfly
x = 1:10^4; y = rand(length(x));

function rungadfly(x, y)
@time Gadfly.draw(Gadfly.SVGJS(IOBuffer(), Gadfly.default_plot_width, Gadfly.default_plot_height, false), Gadfly.plot(x=x, y=y, Gadfly.Geom.point))
end

rungadfly(x, y)
clear_malloc_data()
rungadfly(x, y)
```
this patch series eliminates all lines in Gadfly proper that allocate more than 1 million bytes. Keep in mind that there are quite a few more lines in Compose and Iterator that allocate such large amounts of memory, and these are not addressed by this patch series. So you should expect the overall performance improvement to be modest (I think I measured 3-fold, but I can't remember for sure), because there are still really big targets left to tackle.

**This is a WIP because it doesn't pass its tests**. It gets quite far, but barfs on `Rendering percent on svgjs backend.` with the error `ERROR: no method convert(Type{Float64}, Percent)`. This is due to my changes to `apply_coordinate` (the last patch in the series). I'm not really sure whether one could predict the proper type of `xmin` and `xmax` at the outset (it seems like that should be possible), but at this point I got to where I (1) need to move to other things, and (2) might benefit from some input by someone more knowledgeable about the internals.