Very slow on Android
Monkey Targets Forums/Android/Very slow on Android
| ||
So I managed to get my app running on an Android phone and whilst the action sections run smoothly enough the loading and processing of data is unbelievably slow. For instance, when setting up my football fixtures I get wait times like this... Flash & HTML: 1 second iPad 2: 3 secs iPhone 3GS: 11 secs San Fran II: 115 secs (Android 2.3.5, 800mhz, 512 ram) Pound for pound the Android phone has better specs than the iPhone but is 10 times slower when the processor has to grind out results (as I say the action sections are fine). Is this normal? It feels as though the game is running in debug mode but I set the build option to release. Am I missing something? |
| ||
r u creating loadsa garbage? |
| ||
I do create around 3,000 fixture objects that are stored in arrays. So you think it is a GC issue? |
| ||
Are you sure you did not generate a debug build? It looks like a GC issue to me too. Declaring an array seems to alocate an object and this can feed the GC. Reuse them as much as possible... |
| ||
Aha! When I remove the command to save the game data the fixtures are processed in less than a second, so it's nothing to with the object creation. Here's how the game data is saved... Method SaveCareer() Local savestr:String ' Global data savestr=GetGlobalData()+";" ' Player data savestr+=GetPlayerData()+";" ' Club data savestr+=GetClubData()+";" ' Competition data savestr+=GetCompetitionData()+";" savestr+="<END>" SaveState(savestr) End ' An example of the data that is being saved Method GetCompetitionData:String() Local savestr:String For Local c:TCompetition = EachIn TCompetition.glist ' Store comp id savestr+=c.id+"," ' Then save teampool For Local tp:TTeamPool = EachIn c.teampool For Local td:TTableData = EachIn tp.pool savestr+=td.GetWriteData() Next savestr+="*" Next savestr+="," ' Then save fixtures For Local f:TFixture = EachIn c.lfixturelist savestr+=f.GetWriteData() Next savestr+="@" Next Return savestr End Class TFixture Method GetWriteData:String() Local str:String str+=sdate+"/" str+=matchtype+"/" str+=round+"/" str+=groupno+"/" str+=leg+"/" str+=hometeam+"/" str+=awayteam+"/" str+=result+"/" str+=resulttype+"/" str+=score1+"/" str+=score2+"/" str+=penscore1+"/" str+=penscore2+"/" str+=level+"/" str+=compid+"?" Return str End End Parsing all of the data from LoadState is pretty quick, so it's just the creation/storing of the string that takes time (2 mins for less than a MB!). What's going on? Edit: I just tested it again but only removed the SaveState(savestr) command and it still took 2 mins to create the savestr. So it's nothing to do with storing the data but rather the concatenation of one large string. |
| ||
monkey has its own string class, I think even in Java Maybe the string implementation isnt done in the most efficient manner? |
| ||
Do any of the individual GetXXXData () calls take longer than the others? How long does it take if you just call GetCompetitionData, for example, since we can see what's in that? |
| ||
Maybe the string implementation isnt done in the most efficient manner? correct, it's not. monkey strings are immutable, so a new string is created EVERY time you add something new to the old string. That's a LOT of work to do and a lot of object creation. How to get around this? That i have no idea. - Try adding ALL values into one line: Local savestr:String ' Global data savestr=GetGlobalData()+";"+GetPlayerData()+";"+GetClubData()+";"+GetCompetitionData()+";"+"<END>" SaveState(savestr) - my other thought would be to use a string array instead of one large string in your EachIn tppool loop. THAT is the culprit! |
| ||
If that's the case, String.Join might help (if you can put the strings into an array rather than a list, perhaps resizing it when necessary). String.Join looks like this in lang.java...static public String join( String sep,String[] bits ){ StringBuffer buf=new StringBuffer(); for( int i=0;i<bits.length;++i ){ if( i>0 ) buf.append( sep ); buf.append( bits[i] ); } return buf.toString(); } A quick Google shows that StringBuffer is mutable, and it looks like it'd all get done a lot quicker. (It would appear that buf.append is just a case of more memory being allocated, not new objects.) |
| ||
Yep, String.Join makes a MASSIVE difference over manually joining strings together... Run this for STDCPP (you may need to change the SaveString filepath at the bottom of this code if on Mac, etc, if you want to check the output); it takes around 10 seconds for me with USE_JOIN set to False. Then run it with USE_JOIN set to True... it's almost instant! I'd imagine something like this to try and minimise the work needed: Method GetCompetitionData:String() Local savestr:String [REASONABLE_NUMBER, or count list items first!] ... then, rather than... savestr+=td.GetWriteData() ... something like: savestr[index]=td.GetWriteData() ' For each savestr+=whatever index = index + 1 ' If not pre-calc'ing array size... If index > savestr.Length - 1 Then savestr = savestr.Resize [savestr.Length * 2] ' Double it! Join at the end of the method and return the string. For GetWriteData, it'd be something like this: Method GetWriteData:String() Local str:String [15] str[0]=sdate+"/" str[1]=matchtype+"/" ... etc... Local result:String = result.Join [str] Return result |
| ||
Hi, Monkey does use java strings, this is really just a 'big O' problem. If you are concatenating many strings together, try using a StringStack as a temporary buffer, eg: Local buf:=New StringStack buf.Push "Blah" buf.Push "Etc" ...etc... Local result:=buf.Join( "" ) |
| ||
@James That method has made a massive improvement! Got the saving time to around 25 seconds and there are probably a few other areas that I can sharpen up. Cheers! @Mark Thanks. I will try using a StringStack in the morning and see how it compares to James' method. :) |
| ||
Excellent, though 25 seconds is still a long time. StringStack does look easier! |
| ||
Yep, StringStack is even faster. Down to 4 seconds! Cheers guys. |
| ||
Mark, Can we get a constructor for String that takes an Int array? Basically it would just do String.FromChar on each of the elements and concatenate them without creating extra String objects for each one. Similar to Java's String(char[]) constructor. Going the other way with a String.ToCharArray would be nice too. Edit: Like the BuildString function in Diddy: http://code.google.com/p/diddy/source/browse/trunk/src/diddy/functions.monkey It's externed in Java, but implemented in Monkey for other targets. |
| ||
Yep, StringStack is even faster. Down to 4 seconds! Cheers guys. Brilliant result! |