sciapp / gr

GR framework: a graphics library for visualisation applications
Other
329 stars 54 forks source link

GR is slower than MPL #158

Closed Z1nK closed 2 years ago

Z1nK commented 2 years ago

Good day, We tried GR on python in the hope that it will increase performance. But GR in our environment is slower than matplotlib. system: RHEL 8.5. Nvidia Quadro P2000. Everything from the required list is installed

In simple tests, GR twice slower than MPL('Qt5Agg' backend)

in that test for example I have ~23 fps(GR) vs ~68 fps(mpl)) In potting simple graphs, like 2000 - 10 000 points: MPL plot it in average 0.15 seconds GR plot the same in average 0.3 seconds

Any suggestions what I might have missed?

jheinen commented 2 years ago

It looks like current MPL versions no longer display all frames. To make a fair comparison, you would have to adjust the example as follows:

for i in range(num_frames):
    line.set_ydata(sin(x + i / 10.0))
    line.axes.figure.canvas.draw()
    draw()
    pause(0.0001)

This then leads to the following result (on my iMac):

fps  (GR):  207
fps (mpl):   49
  speedup:    4.2

I have adapted the anim.py example in the development branch accordingly.

Z1nK commented 2 years ago

I will try this and post what I get.

what about simple plotting test, I used a simple program:

from timeit import default_timer as timer
import numpy as np

step = 0.1

t = np.arange(0.0, 1000.0, step)
s = 1 + np.sin(0.05 * np.pi * t)
print("points in t: {}".format(len(t)))

mpl_time = 0
GR_time = 0

if(True):
    import matplotlib.pyplot as plt
    from  matplotlib import use
    use('Qt5Agg')
    tstart = timer()
    fig, ax = plt.subplots()
    ax.plot(t, s)
    ax.grid()
    plt.show(block=False)
    tstop = (timer() - tstart)
    mpl_time=tstop
    print("mpl elapsed time {}".format(tstop))

if(True):
    from gr.pygr import mlab
    tstart = timer()
    mlab.plot(t, s)
    tstop = (timer() - tstart)

    GR_time=tstop
    print("GR elapsed time {}".format(tstop))

f = open("MPL_GR_test.txt", "a")
f.write("{} {} {}\n".format(mpl_time, GR_time, len(t)) )
f.close()
input("Press any key to quit ...")

This code give me the followings: MPL plot it in average 0.15 seconds GR plot in average 0.3 seconds

@jheinen if it possible, what will be the result of this code on your iMac?

jheinen commented 2 years ago

I think, you are (only) measuring the window creation time (which seems to be longer in GR). Please compare your results with this example:

from timeit import default_timer as timer
import numpy as np

step = 0.1

t = np.arange(0.0, 1000.0, step)
s = 1 + np.sin(0.05 * np.pi * t)
print("points in t: {}".format(len(t)))

mpl_time = 0
GR_time = 0

if(True):
    import matplotlib.pyplot as plt
    from  matplotlib import use
    use('Qt5Agg')
    tstart = timer()
    fig, ax = plt.subplots()
    for i in range(100):
        ax.clear()
        ax.plot(t, s)
        ax.grid()
        plt.show(block=False)
    tstop = (timer() - tstart)
    mpl_time=tstop
    print("mpl elapsed time {}".format(tstop))

if(True):
    from gr.pygr import mlab
    tstart = timer()
    for i in range(100):
        mlab.plot(t, s)
    tstop = (timer() - tstart)

    GR_time=tstop
    print("GR elapsed time {}".format(tstop))

f = open("MPL_GR_test.txt", "a")
f.write("{} {} {}\n".format(mpl_time, GR_time, len(t)) )
f.close()
input("Press any key to quit ...")

The results on my iMac:

points in t: 10000
mpl elapsed time 1.7292792070657015
GR elapsed time 0.37192431511357427
Press any key to quit ...
jheinen commented 2 years ago

If you ignore the window creation time (both for MPL and GR), you get the following results:

points in t: 10000
mpl elapsed time 0.04142537200823426
GR elapsed time 0.004014506936073303
Press any key to quit ...

Python code:

from timeit import default_timer as timer
import numpy as np

step = 0.1

t = np.arange(0.0, 1000.0, step)
s = 1 + np.sin(0.05 * np.pi * t)
print("points in t: {}".format(len(t)))

mpl_time = 0
GR_time = 0

if(True):
    import matplotlib.pyplot as plt
    from  matplotlib import use
    use('Qt5Agg')
    fig, ax = plt.subplots()
    ax.plot(t, s)
    ax.grid()
    tstart = timer()
    fig, ax = plt.subplots()
    ax.plot(t, s)
    ax.grid()
    plt.show(block=False)

    plt.show(block=False)
    tstop = (timer() - tstart)
    mpl_time=tstop
    print("mpl elapsed time {}".format(tstop))

if(True):
    from gr.pygr import mlab
    mlab.plot(t, s)
    tstart = timer()
    mlab.plot(t, s)
    tstop = (timer() - tstart)

    GR_time=tstop
    print("GR elapsed time {}".format(tstop))

f = open("MPL_GR_test.txt", "a")
f.write("{} {} {}\n".format(mpl_time, GR_time, len(t)) )
f.close()
input("Press any key to quit ...")
Z1nK commented 2 years ago

well animation example in my case did not give a completely positive result(GR still slower), but the gap was greatly reduced.

the first plotting example with for loop:

    for i in range(100):
        ax.clear()
        ax.plot(t, s)
        ax.grid()
        plt.show(block=False)
    ...
    for i in range(100):
        mlab.plot(t, s)

Also did not give results similar to yours.

points in t: 10000
mpl elapsed time 1.525112692033872
GR elapsed time 3.1185102451127023
Press any key to quit ...

The last example shows a good result if after creating the window I wait a bit. The same example as yours, just sleep(0.1) added between plotting.

from timeit import default_timer as timer
import numpy as np

from time import sleep

step = 0.1

t = np.arange(0.0, 1000.0, step)
s = 1 + np.sin(0.05 * np.pi * t)
print("points in t: {}".format(len(t)))

mpl_time = 0
GR_time = 0

if(True):
    import matplotlib.pyplot as plt
    from  matplotlib import use
    use('Qt5Agg')
    fig, ax = plt.subplots()
    ax.plot(t, s)
    ax.grid()
    sleep(0.1)
    tstart = timer()
    fig, ax = plt.subplots()
    ax.plot(t, s)
    ax.grid()
    plt.show(block=False)

    plt.show(block=False)
    tstop = (timer() - tstart)
    mpl_time=tstop
    print("mpl elapsed time {}".format(tstop))

if(True):
    from gr.pygr import mlab
    mlab.plot(t, s)
    sleep(0.1)
    tstart = timer()
    mlab.plot(t, s)
    tstop = (timer() - tstart)

    GR_time=tstop
    print("GR elapsed time {}".format(tstop))

f = open("MPL_GR_test.txt", "a")
f.write("{} {} {}\n".format(mpl_time, GR_time, len(t)) )
f.close()    
input("Press any key to quit ...")

40 experiments, MPL in average: 0.027946423 GR in average: 0.000588588

The effect is stable if "sleep" is at least 0.1 s, when rebuilding with a higher frequency, the time sometimes starts to approach 0.03 s. without "sleep" the time in 99% of experiments is around 0.03 seconds.

If you have any idea why it behaves like this, i will be grateful. If not, i think this issue can be closed.

jheinen commented 2 years ago

Please also pay attention to the visual graphic output. If the sleep commands are in the wrong place, the system will not perform a context switch and the image will not be updated.

As long as the graphics window has been mapped by the window manager, the output is usually an order of magnitude faster in GR.

If the time to build the window is too long for your use case, MPL is probably the better alternative. GR was designed for real-time graphics, both for interactive applications and when creating in-memory video animations.

Z1nK commented 2 years ago

Thank you very much for the clarifications. We will take this feature into account during development.