What i did was basically, collected statistics on running a computation against the standard matrix multiplication which is highly parallel. There are 3 programs i created using the normal iterative-approach i.e. for-loop, greenlet and lastly eventlet implementation.
Overall, i find that greenlet is much more suitable to eventlet (w.r.t time) and the iterative-approach (w.r.t flexibility and elegance). I include my scripts below at the end of this post.
Here's how i executed and profiled my script:
ray:~ ray$ python -m cProfile -o eventletprof_10 ./myEventletDemo.py
Sum of matrix multiplication: 285
ray:~ ray$ python -m cProfile -o eventletprof_100 ./myEventletDemo.py --i 100
Sum of matrix multiplication: 328350
ray:~ ray$ python -m cProfile -o eventletprof_1000 ./myEventletDemo.py --i 1000
Sum of matrix multiplication: 332833500
ray:~ ray$ python -m cProfile -o eventletprof_10000 ./myEventletDemo.py --i 10000
Sum of matrix multiplication: 333283335000
ray:~ ray$ python -m cProfile -o eventletprof_100000 ./myEventletDemo.py --i 100000
Sum of matrix multiplication: 333328333350000
...
...
ray:~ ray$ python -m cProfile -o noneventletprof_10 ./myNoneventletDemo.py
iteration version of matrix add: 285
ray:~ ray$ python -m cProfile -o noneventletprof_100 ./myNoneventletDemo.py --i 100
iteration version of matrix add: 328350
ray:~ ray$ python -m cProfile -o noneventletprof_1000 ./myNoneventletDemo.py --i 1000
iteration version of matrix add: 332833500
ray:~ ray$ python -m cProfile -o noneventletprof_10000 ./myNoneventletDemo.py --i 10000
iteration version of matrix add: 333283335000
ray:~ ray$ python -m cProfile -o noneventletprof_100000 ./myNoneventletDemo.py --i 100000
iteration version of matrix add: 333328333350000
...
...
ray:~ ray$ python -m cProfile -o greenletprof_10 ./myGreenletDemo.py
iteration version of matrix add: 285
ray:~ ray$ python -m cProfile -o greenletprof_100 ./myGreenletDemo.py --i 100
iteration version of matrix add: 328350
ray:~ ray$ python -m cProfile -o greenletprof_1000 ./myGreenletDemo.py --i 1000
iteration version of matrix add: 332833500
ray:~ ray$ python -m cProfile -o greenletprof_10000 ./myGreenletDemo.py --i 10000
iteration version of matrix add: 333283335000
ray:~ ray$ python -m cProfile -o greenletprof_100000 ./myGreenletDemo.py --i 100000
iteration version of matrix add: 333328333350000
What profiling does is to output the results into a file (e.g. greenletprof_100000) and you can view the statistics in the Python interpreter using the following:
And you'll see the statistics printed in much detail. However, this is rather tedious so i would suggest a graphical UI to view the profiled data instead and one such option is RunSnakeRun.
Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pstats
>>> profiledData = pstats.Stats('greenletprof_100000')
>>> profiledData.print_stats()
Comparing the statistics in detail between the different runs reveals that the iterative approach is the most efficient followed by Greenlet and last eventlet. Here are the statistics in detail:
>>> import pstats
>>> stats10 = pstats.Stats('nongreenleteventlet100000.profile')
>>> stats10.print_stats()
Sun May 10 22:30:16 2009 nongreenleteventlet100000.profile
6 function calls in 0.069 CPU seconds
Random listing order was used
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.060 0.060 0.069 0.069 /home/tayboonl/Desktop/Greenlet_Eventlet/nongreenleteventletdemo.py:8(execMatrixAdd_Iter)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.069 0.069:1( )
3 0.009 0.003 0.009 0.003 {range}
...
>>> stats10 = pstats.Stats('greenlet100000.profile')
>>> stats10.print_stats()
Sun May 10 22:16:45 2009 greenlet100000.profile
500011 function calls in 1.511 CPU seconds
....
>>> stats10 = pstats.Stats('eventlet100000.profile')
>>> stats10.print_stats()
Sun May 10 22:20:17 2009 eventlet100000.profile
6500027 function calls (5800031 primitive calls) in 34.901 CPU seconds
You might have noticed the remarkable number of functions calls made in the scenario using Eventlet. It suffice at this point for me to say is that Eventlet was not designed for high performance computing w.r.t Greenlet since it was designed to be a asynchronous networking library and to me, it makes alot of sense to always profile the application or framework before using it on a wide basis.
In case you are interested, here are the scripts i used
All together, there are 3 in total first being that implemented using Greenlet (Cool stuff!)
#!/usr/bin/python
import greenlet
import optparse
tasks = []
accum = list()
sum = 0
vecA = vecB = None
def mulNAccum(idx, val1, val2) :
global accum
accum.insert(idx, val1*val2)
#print idx,val1*val2,accum
def createTasks(HowMany):
global vecA, vecB
vecA = range(0, HowMany)
vecB = range(0, HowMany)
for i in range(0,HowMany):
tasks.append(greenlet.greenlet(run=mulNAccum,parent=greenlet.getcurrent()))
def executeTasks(HowMany):
global tasks
global accum
global sum
for i in range(0,HowMany):
tasks[i].switch(i, vecA[i],vecB[i])
#print "tasks finished executing ...\n"
# print accum
for i in range(0, len(accum)):
sum = sum + accum[i]
print "Sum of matrix multiplication: %d\n" % sum
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("--items", "-i", default=10, action="store", type="int", dest="HowMany", help="number of elements in matrix array to process")
(options, args) = parser.parse_args()
createTasks(options.HowMany)
executeTasks(options.HowMany)
Similar program using the for-loop a.k.a iterative approach
#!/usr/bin/python
import optparse
sum = 0
vecA = vecB = None
def execMatrixAdd_Iter(HowMany):
global vecA, vecB, sum
vecA = range(0, HowMany)
vecB = range(0, HowMany)
for i in range(0, HowMany):
temp = vecA[i] * vecB[i]
sum = temp + sum
print "iteration version of matrix add: %d\n" % sum
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("--items", "-i", default=10, action="store", type="int", dest="HowMany", help="number of elements in matrix array to process")
(options, args) = parser.parse_args()
execMatrixAdd_Iter(options.HowMany)
Last script using Linden Lab's eventlet
#!/usr/bin/python
import eventlet
import eventlet.api
import optparse
tasks = []
accum = list()
sum = 0
vecA = vecB = None
def mulNAccum(idx, val1, val2) :
global accum
accum.insert(idx, val1*val2)
#print idx,val1*val2,accum
def createTasks(HowMany):
global vecA, vecB
vecA = range(0, HowMany)
vecB = range(0, HowMany)
for i in range(0,HowMany):
tasks.append(eventlet.api.spawn(mulNAccum, i, vecA[i-1], vecB[i-1]))
def executeTasks(HowMany):
global tasks
global accum
global sum
for i in range(0,HowMany):
tasks[i].switch()
#print "tasks finished executing ...\n"
# print accum
for i in range(0, len(accum)):
sum = sum + accum[i]
print "Sum of matrix multiplication: %d\n" % sum
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("--items", "-i", default=10, action="store", type="int", dest="HowMany", help="number of elements in matrix array to process")
(options, args) = parser.parse_args()
createTasks(options.HowMany)
executeTasks(options.HowMany)
0 comments:
Post a Comment