speed issues - app is very slow

2,083 views
Skip to first unread message

mark...@googlemail.com

unread,
Jul 1, 2014, 10:53:30 AM7/1/14
to kivy-...@googlegroups.com
Hello,

i have big issues with my kivy app on mobile devices. The problem is that it is simply extremely slow. On the pc its no issue but as I'm developing for mobile I really need to improve that. 
Is there any manual/tutorial on how to make code more efficient? 
I have only few pictures. Unfortunately I'm not a trained programmer, but I tried a lot of stuff to improve the code but I cant really mange to increase the speed.

I add a screenshot of the webdebugger and a cProfile file, maybe that will help to understand what I am doing wrong.


myapp.profile

Alexander Taylor

unread,
Jul 1, 2014, 12:22:51 PM7/1/14
to kivy-...@googlegroups.com
Are you able to post your actual code (e.g. link to github repo)? There are lots of things that might help, but it's a lot easier if we can see what you'rea actually doing!

mark...@googlemail.com

unread,
Jul 1, 2014, 12:43:03 PM7/1/14
to kivy-...@googlegroups.com
I can't really post the code, it's the whole app which is close to be done. Therefore I'm not really allowed to put it online.
But one thing that is very slow is a table I create, that code I can put. 
def exp_pop(self, *args):
Label.color=[1,1,1,1]
experiment= mydict[ 'key']
self.exppop_box= GridLayout(cols=1,size_hint_y=None,height=(int(len(experiment)*0.08*self.height)))
layout={}
for key in range(len(experiment)):
layout[experiment[key][0]] = GridLayout(rows=1)
btn=[]
Button.color= PhenoTypeApp.grey3
for a in range(len(experiment[key])):
btn.append(ToggleButton(text=str(experiment[key][a]),\
background= 'backgrounds/table_seperator.jpg', \
font_size=(str(self.height*0.04) + 'sp'),text_size = (self.width*0.15, None)))
layout[experiment[key][0]].add_widget(btn[a])
self.exppop_box.add_widget(layout[experiment[key][0]])
Button.color = [1,1,1,1]
scroll=ScrollView()
scroll.add_widget(self.exppop_box)
head_grid=GridLayout(rows=1,size_hint=(1,None),height=(0.05*self.height))
head=[]
head.append(Button(text='head1',text_size = (self.width*0.15, None),bold=True,font_size=(str(self.height*0.04) + 'sp')))
head.append(Button(text='head2',text_size = (self.width*0.15, None),bold=True,font_size=(str(self.height*0.04) + 'sp')))
head.append(Button(text='head3',text_size = (self.width*0.15, None),bold=True,font_size=(str(self.height*0.04) + 'sp')))
head.append(Button(text='head4',text_size = (self.width*0.15, None),bold=True,font_size=(str(self.height*0.04) + 'sp')))
head.append(Button(text='head5',text_size = (self.width*0.15, None),bold=True,font_size=(str(self.height*0.04) + 'sp')))
for b in range(len(head)):
head_grid.add_widget(head[b])
tool_box=BoxLayout(size_hint_y=0.1)
event_box=BoxLayout(size_hint_y=0.1,spacing=0.01*self.height)
events=[]
tools=[]
# tools.append(Button(text='top',background_color= (1,0,0,1)))
# tools.append(Button(text='up',background_color= (1,0,0,1)))
# tools.append(Button(text='down',background_color= (1,0,0,1)))
# tools.append(Button(text='bottom',background_color= (1,0,0,1)))
events.append(Button(text='Remove',text_size = (self.width*0.25, None),font_size=(str(self.height*0.04) + 'sp')))
events.append(Button(text='Modify',text_size = (self.width*0.25, None),font_size=(str(self.height*0.04) + 'sp')))
events.append(Button(text='Cancel',text_size = (self.width*0.25, None),font_size=(str(self.height*0.04) + 'sp')))
# for c in range(4):
# tool_box.add_widget(tools[c])
for c in range(3):
event_box.add_widget(events[c])
main_box=BoxLayout(orientation='vertical')
main_box.add_widget(head_grid)
main_box.add_widget(scroll)
# main_box.add_widget(tool_box)
main_box.add_widget(event_box)
self.exp_popup= Popup(title='MyPopup',title_size=self.button_font_size,separator_color=PhenoTypeApp.mark3, content=main_box, size_hint=(0.95,0.95))
events[2].bind(on_press=self.exp_popup.dismiss)
self.exp_popup.open()



I would be happy about any hint. do you think the amount of python objects is the issue? that seems very high to me.

Bill Janssen

unread,
Jul 2, 2014, 11:51:03 PM7/2/14
to kivy-...@googlegroups.com
Python objects are OK, but widgets are expensive.  The simplest thing to do to speed this up is to create fewer widgets at any one time.  Creating and postioning and sizing lots of widgets is slow, so try to create some of them in an event callback.  Or create the widgets before you open your first window.

Bill

mark...@googlemail.com

unread,
Jul 3, 2014, 6:39:39 PM7/3/14
to kivy-...@googlegroups.com
Thank you very much for your answer. the thing is, that i would like to work with big tables,for the table itself it might be ok, to load few entries at a time (how many do you think is acceptable) and load them with an event. but showing a spinner with over 200 entires also becomes very slow. I am using kivy for the development of a scientific app which should handle some data, which from the python part should be no big deal, but visualising now really makes a challenge for me. On an ordinary android tablet the app needs over 15 seconds to load, which really is the edge to what one would wait.
Is there any general guideline what things are slow?
I already understood that buttons are slower than labels.
Still I need to show the data in tables which the user should be able to interact with. Does anyone have a hint how to do that more efficiently?

thanks 

Markus

ZenCODE

unread,
Jul 4, 2014, 2:11:44 AM7/4/14
to kivy-...@googlegroups.com
Hi

It might be an idea to do some profiling, so you see exactly and for certain where the most time is being spent. Once you know that, you can know what areas to attack..

http://kivy.org/docs/api-kivy.app.html?highlight=profile

https://docs.python.org/2/library/profile.html

mark...@googlemail.com

unread,
Jul 4, 2014, 2:33:01 AM7/4/14
to kivy-...@googlegroups.com
I couldn't really find out what is the main thing that is slow in the main loop. in my first post i added a profile file. Feel free to check it. Would be great fi you find the problem.

ZenCODE

unread,
Jul 4, 2014, 3:12:48 AM7/4/14
to kivy-...@googlegroups.com
Duh, sorry, missed that...:-) I'll give that a bash this weekend, time allowing.

Smaran

unread,
Jul 6, 2014, 7:27:01 PM7/6/14
to kivy-...@googlegroups.com
Hello,

Maybe application design review could be useful.
Your mobile user will receive the first screen, read and think a few seconds before requesting the second screen and so on.

You could prepare and show the first window and have a running thread building the next window.

mark...@googlemail.com

unread,
Jul 7, 2014, 6:51:12 PM7/7/14
to kivy-...@googlegroups.com
thanks for your answer, that sounds like a good idea. though I'm not quite sure how I can implement this. Can you explain me a bit more detailed how this would be done? I still need to start the main function from the beginning. right? 

mark...@googlemail.com

unread,
Jul 8, 2014, 1:59:41 AM7/8/14
to kivy-...@googlegroups.com
I have read in another post that it is important not to put the wrong code in the wrong place. Can someone elaborate this? should I not place common functions in my app class? Or what does 'wrong place' refer to? Is there a tutorial/manual on best coding practice for kivy?

Ao Yen

unread,
Jul 8, 2014, 9:36:50 AM7/8/14
to kivy-...@googlegroups.com
You're doing way to much stuff in one go! Try to imagine it in this way:

You are planning a massive thanksgiving dinner. 30 family members. So you need to cook a ton a food. Thankfully you're not alone, because your mum and your girlfriend have offered to help you out. The only thing you need to do for them is provide the food and they will cook it.
Because you need to buy so much food there's actually not enough room in your car! You're going to have to make multiple trips to the grocery store.

This is what you are doing with your app right now:
You are going to the grocery store and buying some food. Then you are driving back home and dropping off the food on the drive way. Then you go back and buy some more food. You do this for another 4 trips. When you are finally done, you carry all the food into the kitchen so your mum and girlfriend can finally start to cook. Because you took so long getting all the stuff, they had to wait for you to finish. That took way too long!

This is what your app SHOULD be doing:

Thanksgiving is a massive dinner. But some things can be started earlier. For example, you need to put the turkey in the oven at least 10 hours before you plan to eat it or it won't be thoroughly cooked. So the turkey should be the first thing you buy from the store right? You drive to the store, buy a turkey, veggies, oil, basically all the stuff you need for the turkey. Now you drive back home, hand all the stuff to the women and the kitchen so they can get started. Now you have plenty of time to get the other stuff, which the girls won't need straight away. So while they are busy with the turkey, you fetch the potatoes, gravy, pie, etc... And when the girls have finished with the turkey, there you are ready to hand them the next stuff.

The analogy:
Figure out what your app needs to do first. Then figure out what it needs just after that. And work your way down to the less important tasks. The result will be that your app builds itself incrementally. The user doesn't notice this, all they see is a smooth app.

Smaran

unread,
Jul 8, 2014, 10:08:30 AM7/8/14
to kivy-...@googlegroups.com
Sorry for my English. You read enough on the internet but not always write in English.

Well, before starting coding, think in terms of your mobile user needs.
Have a draft (paper and pencil) of the application screens and navigation.
If things grow with a lot of screens and data, maybe you could get confused.
In this case, a free tool like Freemind (http://freemind.sourceforge.net) could help you organize the project.
Have a name to each screen. Distribute the information across screens.

Try to reduce to a minimum the information on the initial screens. You could even "trick" your user with some question, earning some time.

Your main program should:
1) start a Python threading that will build each Kivy screen object and keep it on a dictionary {'screenName': screenObject}
Your main program and the threading will keep reference of this dictionary.
Dont't wait for it. Go to the second step.
2) show the first screen

When your user requests the second screen, you will get it from the dictionary.
If it is not there, the Kivy clock (or time.sleep ?) can help you wait for some seconds until the thread finish its job.

Hope this help you.
Feel free to ask more questions. 

I believe that someone could elaborate it better.

mark...@googlemail.com

unread,
Jul 9, 2014, 3:35:21 AM7/9/14
to kivy-...@googlegroups.com
Ok guys, I think we're getting closer to the issue ;-) it appears that my build function is the thing that takes way too long. 

def build(self):
self.icon = 'icon.png'
Window.bind(on_keyboard=self.hook_keyboard)
self.sm = ScreenManager(transition=FadeTransition())
self.sm.add_widget(Screen1(name='Screen1'))
self.sm.add_widget(Screen2(name='Screen2'))
self.sm.add_widget(Screen3(name='Screen3'))
self.sm.add_widget(Screen4(name='Screen3'))
self.sm.current = 'Screen1'
return self.sm

Thats how it looks like. As it seems it takes quite long to load all screens at the same time. Can I add the screens also outside the build method? or where should I add them most efficiently? I guess opening the fist and then adding the others would be best. but somehow I can't figure out where.

Thanks so much for all your help! I guess there is more people out there having similar problems.

Markus

Alexander Taylor

unread,
Jul 9, 2014, 6:37:27 AM7/9/14
to kivy-...@googlegroups.com
Use Clock.schedule_once to schedule a loading method at some other time.
> (http://freemind.sourceforge.net <http://freemind.sourceforge.net>)
> <https://lh3.googleusercontent.com/-zjdZSmvzV-4/U7LK6_CxwhI/AAAAAAAAARA/1qzkVtfQHuc/s1600/webdebugger.png>
>
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Kivy users support" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/kivy-users/UgLnn_fB8Xo/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> kivy-users+...@googlegroups.com
> <mailto:kivy-users+...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.

ZenCODE

unread,
Jul 9, 2014, 8:15:42 AM7/9/14
to kivy-...@googlegroups.com
Another option is to just add the first screen on initialization, then create and add the other screens as needed. This was our approach....

mark...@googlemail.com

unread,
Jul 9, 2014, 2:48:56 PM7/9/14
to kivy-...@googlegroups.com
Thanks that helped its faster now.
Although the opening time now varies from 6 to 20 seconds on the same device. I can not really understand why there is such a big difference. 
Any explanations?

ZenCODE

unread,
Jul 12, 2014, 7:00:34 AM7/12/14
to kivy-...@googlegroups.com
Try profiling it again. That should indicate where the slowdown in occurring. That kind of variation should be much easier to detect, Profiling will tel you everything, it's just as the cost of analysis...
Reply all
Reply to author
Forward
0 new messages