Performance question - CPU usage and animating 500 PNGs on screen [ New to Kivy ]

54 views
Skip to first unread message

John Olson

unread,
Dec 1, 2017, 5:41:42 PM12/1/17
to Kivy users support
At my work, we're doing some performance evaluation tests with several technologies for a new hardware product (ARM/Linux based).  I came across Kivy and it seemed very approachable.  My first tests were on my Mac laptop using simple video, and then using widgets with .kv files.  My next test was to animate Widgets on screen. Once I started doing a typical game loop (using Clock), CPU usage on my Mac laptop (running High Sierra) went through the room (65% for only 500 objects). I think I must be doing something wrong.


Here is my code. I appreciate any helpful feedback. I've been scouring the forums and other sources looking for other samples. I've found a few games, etc but even those have pretty high CPU usage.

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.clock import Clock
from random import random
from kivy.core.window import Window
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.image import Image

class PerfTest(App):

def build(self):
return Perf()


class Cat():
posX = NumericProperty(0)
posY = NumericProperty(0)
velX = NumericProperty(0)
velY = NumericProperty(0)

class Perf(FloatLayout):

cats = []
texture = ObjectProperty()

def __init__(self, **kwargs):
super(Perf, self).__init__(**kwargs)

img= Image(source="cat.png")
self.texture = img.texture

for x in range(0,500):
cat = Cat()
cat.posX = random() * Window.width
cat.posY = random() * Window.height
cat.velX = -5 + random() * 10
cat.velY = -5 + random() * 10
self.cats.append(cat)

Clock.schedule_interval(self.update, 1.0/60.0)


def update(self, dt):

with self.canvas.before:
self.canvas.clear()

with self.canvas:

for c in self.cats:
c.posX = c.posX + c.velX
c.posY = c.posY + c.velY
if c.posX < 0:
c.posX = Window.width
elif c.posX > Window.width:
c.posX = 0
if c.posY < 0:
c.posY = Window.height
elif c.posY > Window.height:
c.posY = 0
Rectangle(texture=self.texture, pos=(c.posX,c.posY), size=(64,64))

if __name__ == "__main__":
PerfTest().run()










Alexander Taylor

unread,
Dec 2, 2017, 9:07:17 AM12/2/17
to Kivy users support
Your update method is very inefficient, as it clears the canvas and re-adds many Rectangles each frame. Instead you should save references to the rectangles (`self.rects.append(Rectangle(...))` or similar), and update them later (`for rect in self.rects: rect.pos  = (c.posX, c.posY)` etc.). This is very significantly faster.

You might also be interested in KivEnt (http://kivent.org/), a game engine for Kivy. Its rendering is extremely fast, achieved by using Kivy's low level graphics API very efficiently.

John Olson

unread,
Dec 3, 2017, 1:20:42 AM12/3/17
to Kivy users support
Thank you Alexander.  That helped. I was mis-using Rectangle thinking it was more of draw call instruction, so I didn't think of saving a reference to it.  I tried the change and it definitely improved performance ( tested on another computer and dropped CPU by 1/2 down to 12.4% from 26%), but still seems a bit high for a simple test. I may have to look at KivEnt more.

- John O
Reply all
Reply to author
Forward
0 new messages