I'm sorry to have used the term "useless" since it was not what I meant. In 
fact, after profiling the simple draw example, I realized there were a lot of 
necessary operations that were not quite visible from my "external" point of 
view. I was just thinking "why the hell is it so slow to draw some lines and 
ticks". I think you explained very clearly the actual situation. Also, I've 
been coded glumpy that mix matplotlib and OpenGL (for imshow operations only) 
quite efficiently and I thought something similar could be done for regular 
plot. Anyway, I will try to code further the GL backend without paying too much 
attention to speed right now.

Thanks a lot for all the explanations.


Nicolas


On Jul 29, 2011, at 6:05 PM, Michael Droettboom wrote:

> Nicolas,
> 
> I'm not sure how you've reached your conclusion.
> 
> The 21,000 calls to Line2D.draw (i.e. 21 per frame) are easily explained 
> since each grid line (or tick) is in fact a line.
> 
> The 10,000 calls to Tick.draw (i.e. 10 per frame) are because there are 10 
> tick labels.
> 
> likewise for Text.draw etc. and on down the list.
> 
> I don't see how any of these objects could be drawn without calling draw. ;)  
> There actually already is caching that occurs rendering text, for example.  
> None of these calls are strictly "useless".
> 
> If animation speed is important, there are tricks in the examples/animation 
> directory that show how to reuse the ticks from a previous draw and only 
> update the data (i.e. eliminate many of these "useless" draw calls).  But 
> they are tricks -- they don't work for the general case of "anything in this 
> plot may change at any time".
> 
> But I think you are comparing apples to oranges in your speed comparison.  
> You say a "do-nothing" loop in PyOpenGL runs at around 2000 fps, and a 
> "do-nothing" loop in matplotlib runs about 100fps.  But, of course, the 
> matplotlib test case is actually doing a great deal even with the backend 
> doing nothing -- it is doing all of the work of laying out the plot, which is 
> the majority of time spent getting a plot to the screen.  And that all work 
> happens in Python -- its speed is what it is and is acceptable in many 
> contexts -- but no backend work is going to improve what's going on in the 
> core.
> 
> I should warn you that previous attempts to speed up matplotlib using 
> hardware acceleration have failed to produce much fruit because the backends 
> actually do fairly little work by design in matplotlib.  The actual act of 
> rendering paths into pixels on screen (i.e. what happens in the backend) is a 
> small fraction of the run time, even when using a software renderer (eg. 
> Agg).  Here's a useful benchmark that renders a plot a bunch of times to 
> memory:
> 
>   import sys
>   import matplotlib
>   matplotlib.use(sys.argv[-1])
>   from pylab import *
>   import numpy
>   plot(numpy.arange(int(sys.argv[-2])))
>   for i in xrange(1000):
>       draw()
> 
> and the results (on my 2.33GHz Intel E6550):
> 
> > time python test_backend_speed.py 3 agg
> 
> real    0m15.211s
> user    0m15.009s
> sys     0m0.136s
> 
> # Here "backend_pyglet" is the do-nothing backend you sent to the list in a 
> previous e-mail
> > time python test_backend_speed.py 3 module://backend_pyglet
> 
> real    0m14.038s
> user    0m13.713s
> sys     0m0.256s
> 
> > time python test_backend_speed.py 100 agg
> 
> real    0m23.038s
> user    0m22.845s
> sys     0m0.132s
> 
> > time python test_backend_speed.py 100 module://backend_pyglet
> 
> real    0m15.251s
> user    0m14.837s
> sys     0m0.304s
> 
> So you see the actual work in the backend can be a fairly small fraction of 
> the total runtime -- that gives one an idea of the upper bound on the speed 
> improvement that any backend could make without digging into the matplotlib 
> core and making improvements there.
> 
> In fairness, my test is not measuring the time to (once rendering the plot) 
> blit it to the screen.  I suspect OpenGL will have an advantage there.  It 
> may even be possible as a mid-way solution to create an Agg/OpenGL backend 
> that used Agg for rendering and OpenGL -- that's something that would be 
> really useful just to have another nice cross-platform GUI backend.
> 
> The other important thing to note about this benchmark is that as the size of 
> the data increases, the proportion of time spent in the backend increases.
> 
> I'm also worried (and I have no numbers to back this up) that a pyglet or 
> PyOpenGL backend may actually be slower if the work to convert paths from 
> matplotlib's path.Path format to the format understood by pyglet and/or 
> PyOpenGL happens in Python, as your preliminary code backend_pyglet.py does 
> in draw_path (i.e. looping over each vertex in a Python loop.)  In the Agg 
> backend, that happens in C++ on-the-fly without copying the data -- see 
> src/path_converters.h.  This code is exposed to Python through 
> matplotlib._path.cleanup_path, but that does require copying memory, which 
> for large data sets may be a limiting factor.  So you may end up needing to 
> write the backend in C++ to really beat the current Agg backend, but I'd love 
> to be proven wrong.
> 
> I hope this helps to better illustrate what you're seeing, and I don't mean 
> to discourage you in implementing an OpenGL-based backend (which would be 
> very nice to have for portability reasons among others).  But I hope this 
> also illustrates that if the end goal is simply to "go faster", this may be 
> somewhat like putting racing tires on a car without replacing the engine.
> 
> Cheers,
> Mike
> 
> On 07/29/2011 03:09 AM, Nicolas Rougier wrote:
>> 
>> 
>> 
>> I just did it using the regular python profiler (and a pyglet backend 
>> because glut cannot be easily profiled).
>> Here are some results for exactly 1000 frames displayed:
>> 
>> > python -m cProfile  -s cumulative test_backend_pyglet.py
>>          7723453 function calls (7596399 primitive calls) in 16.583 seconds
>> 
>>    Ordered by: cumulative time
>> 
>>    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
>>         1    0.004    0.004   16.587   16.587 
>> test_backend_pyglet.py:1(<module>)
>>         1    0.000    0.000   14.000   14.000 pyplot.py:123(show)
>>         1    0.000    0.000   14.000   14.000 backend_pyglet.py:214(show)
>>         1    0.000    0.000   13.951   13.951 __init__.py:115(run)
>>         1    0.000    0.000   13.951   13.951 base.py:117(run)
>>         1    0.009    0.009   13.949   13.949 base.py:149(_run_estimated)
>>      1000    0.018    0.000   13.639    0.014 base.py:244(idle)
>> 1119/1116    0.009    0.000   13.378    0.012 event.py:318(dispatch_event)
>>      1004    0.006    0.000   13.340    0.013 
>> __init__.py:1148(dispatch_event)
>>      1000    0.002    0.000   13.326    0.013 backend_pyglet.py:319(on_draw)
>>      1000    0.013    0.000   13.324    0.013 backend_pyglet.py:324(draw)
>>      1000    0.004    0.000   13.001    0.013 
>> backend_pyglet.py:342(_render_figure)
>> 60000/1000    0.204    0.000   12.977    0.013 artist.py:53(draw_wrapper)
>>      1000    0.023    0.000   12.970    0.013 figure.py:805(draw)
>>      1000    0.046    0.000   12.775    0.013 axes.py:1866(draw)
>>      2000    0.046    0.000   11.791    0.006 axis.py:1029(draw)
>>     10000    0.098    0.000    8.521    0.001 axis.py:219(draw)
>>     21000    0.710    0.000    6.467    0.000 lines.py:463(draw)
>>     20000    0.030    0.000    2.301    0.000 
>> transforms.py:2234(get_transformed_points_and_affine)
>>     21000    0.093    0.000    2.245    0.000 transforms.py:2224(_revalidate)
>>         1    0.001    0.001    2.081    2.081 pylab.py:1(<module>)
>>         1    0.001    0.001    2.080    2.080 pylab.py:215(<module>)
>>      12/6    0.007    0.001    2.036    0.339 {__import__}
>>         1    0.001    0.001    1.937    1.937 pyplot.py:15(<module>)
>>         1    0.000    0.000    1.935    1.935 __init__.py:14(pylab_setup)
>>         1    0.001    0.001    1.931    1.931 backend_pyglet.py:55(<module>)
>>         1    0.011    0.011    1.929    1.929 __init__.py:94(<module>)
>> 68000/64000    0.450    0.000    1.824    0.000 transforms.py:1732(transform)
>>     15000    0.381    0.000    1.726    0.000 text.py:514(draw)
>>      2000    0.035    0.000    1.711    0.001 axis.py:977(_get_tick_bboxes)
>>     10000    0.091    0.000    1.668    0.000 text.py:713(get_window_extent)
>>     64605    0.694    0.000    1.520    0.000 path.py:83(__init__)
>>     24000    0.067    0.000    1.491    0.000 
>> transforms.py:1155(transform_path_non_affine)
>>     20041    0.435    0.000    1.430    0.000 lines.py:386(recache)
>>     44000    0.118    0.000    1.385    0.000 
>> transforms.py:1761(transform_non_affine)
>>    164452    1.340    0.000    1.340    0.000 {numpy.core.multiarray.array}
>>     20000    0.076    0.000    1.137    0.000 
>> transforms.py:1119(transform_point)
>> 
>> 
>> It does not seem to have superfluous call to the various methods (even if 
>> the plot is a simple 3 points line, there is a lot to draw) and maybe this 
>> means an efficient OpenGL backend would require some cache system to avoid 
>> repeating "useless" operations.
>> 
>> 
>> Nicolas
>> 
>> 
>> On Jul 28, 2011, at 3:15 PM, Michael Droettboom wrote:
>> 
>>> Have you tried running it in the Python profiler?  I find this script [1] 
>>> in combination with kcachegrind to be very useful in answering these kinds 
>>> of questions.
>>> 
>>> [1] http://codespeak.net/pypy/dist/pypy/tool/lsprofcalltree.py
>>> 
>>> Mike
>>> 
>>> On 07/28/2011 07:16 AM, Nicolas Rougier wrote:
>>>> 
>>>> 
>>>> 
>>>> I've created a fork at: 
>>>> https://github.com/rougier/matplotlib/tree/gl-backend
>>>> 
>>>> The name of the backend is glut (it requires OpenGL) and does not display 
>>>> anything, it only measures fps.
>>>> 
>>>> It seems to be stuck at 100fps with the following test script:
>>>> 
>>>> import matplotlib
>>>> matplotlib.use('glut')
>>>> from pylab import *
>>>> plot([1,2,3])
>>>> show()
>>>> 
>>>> while the same do-nothing window directly in pyOpenGL is around 2000fps on 
>>>> the same machine.
>>>> 
>>>> I would like to understand why this is so slow and if it can be fixed.
>>>> 
>>>> 
>>>> 
>>>> Nicolas
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> On Jul 27, 2011, at 3:28 PM, Benjamin Root wrote:
>>>> 
>>>>> 
>>>>> 
>>>>> On Wednesday, July 27, 2011, Nicolas Rougier <nicolas.roug...@inria.fr> 
>>>>> wrote:
>>>>> >
>>>>> >
>>>>> > Hi all,
>>>>> >
>>>>> > I've been testing various idea around the idea of a GL backend, and I 
>>>>> > would have a few questions.
>>>>> > First, I tried to use the backend template to quickly test an empty 
>>>>> > pyglet backend and I've been quite surprised by the bad performances. 
>>>>> > Without drawing anything, I can hardly reach 100FPS and I wonder if I 
>>>>> > did something wrong ? (The backend is available backend_pyglet.py 
>>>>> > <http://www.loria.fr/~rougier/tmp/backend_pyglet.py> and the test file 
>>>>> > is at test_backend_pyglet.py 
>>>>> > <http://www.loria.fr/~rougier/tmp/test_backend_pyglet.py>)
>>>>> >
>>>>> > Second, I've been experimenting with proper anti-alias technics (using 
>>>>> > shaders) and the results are not so bad so far (IMHO) :
>>>>> > Antialiased line with thickness varying by 0.1 pixels:
>>>>> > http://www.loria.fr/~rougier/tmp/aa-line.png
>>>>> > (don't paid attention to the cap, it's not done yet)
>>>>> >
>>>>> > Antialiased circles (small circles position is increased by 0.1 pixels)
>>>>> > http://www.loria.fr/~rougier/tmp/aa-circle.png
>>>>> > (I can post source code if anyone is interested)
>>>>> > I don't know yet if all matplotlib artists can be drawing using these 
>>>>> > technics.
>>>>> >
>>>>> > My question relates to the cairo backend that now seems to support gl 
>>>>> > and shaders. Does anyone know the status of the gl-backend and how it 
>>>>> > would improve performances of matplotlib ? (I had a hard time finding 
>>>>> > any information). 
>>>>> >
>>>>> > Nicolas
>>>>> 
>>>>> Nicolas,
>>>>> 
>>>>> I want to immediately encourage you to continue on your efforts.  PLEASE 
>>>>> make a fork on github so that we may be able to experiment better.
>>>>> 
>>>>> Cheers!
>>>>> Ben Root
>>>> 
>>>> 
>>>> ------------------------------------------------------------------------------
>>>> Got Input?   Slashdot Needs You.
>>>> Take our quick survey online.  Come on, we don't ask for help often.
>>>> Plus, you'll get a chance to win $100 to spend on ThinkGeek.
>>>> http://p.sf.net/sfu/slashdot-survey
>>>> 
>>>> _______________________________________________
>>>> Matplotlib-devel mailing list
>>>> Matplotlib-devel@lists.sourceforge.net
>>>> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
>>> 
>>> 
>>> -- 
>>> Michael Droettboom
>>> Science Software Branch
>>> Space Telescope Science Institute
>>> Baltimore, Maryland, USA
>>> ------------------------------------------------------------------------------
>>> Got Input?   Slashdot Needs You.
>>> Take our quick survey online.  Come on, we don't ask for help often.
>>> Plus, you'll get a chance to win $100 to spend on ThinkGeek.
>>> http://p.sf.net/sfu/slashdot-survey_______________________________________________
>>> Matplotlib-devel mailing list
>>> Matplotlib-devel@lists.sourceforge.net
>>> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
>> 
>> 
>> ------------------------------------------------------------------------------
>> Got Input?   Slashdot Needs You.
>> Take our quick survey online.  Come on, we don't ask for help often.
>> Plus, you'll get a chance to win $100 to spend on ThinkGeek.
>> http://p.sf.net/sfu/slashdot-survey
>> 
>> _______________________________________________
>> Matplotlib-devel mailing list
>> Matplotlib-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
> 
> ------------------------------------------------------------------------------
> Got Input?   Slashdot Needs You.
> Take our quick survey online.  Come on, we don't ask for help often.
> Plus, you'll get a chance to win $100 to spend on ThinkGeek.
> http://p.sf.net/sfu/slashdot-survey_______________________________________________
> Matplotlib-devel mailing list
> Matplotlib-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

------------------------------------------------------------------------------
Got Input?   Slashdot Needs You.
Take our quick survey online.  Come on, we don't ask for help often.
Plus, you'll get a chance to win $100 to spend on ThinkGeek.
http://p.sf.net/sfu/slashdot-survey
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to