Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / Interesting finding - string concatenate is very slow! v1 and v2

Author
Message
Naphier
14
Years of Service
User Offline
Joined: 2nd Oct 2010
Location: St Petersburg, Florida
Posted: 14th Nov 2014 05:15
So the new version of Sudoku In Space has a lot more puzzles being added to it, the smallest level will have 500 puzzles. This means my level selection screen has to handle moving 500 * (2 text objects * 4 sprite object) = 4,000 objects to scroll the screen.
I spent a bit of time working out why it was moving so slow, culling the functions to only move on-screen sprites, and taking out unnecessary calls to sprite functions. After all of that work it was still super slow! Each iteration of moving the sprites was taking 0.11 to 0.15 seconds... Just terrible.

So I did as we do in these situations - isolate the code, write a test, and benchmark.

Well...
Apparently the string concatenation in the for-next loop was really heavy!
I had a line in there like this:
dOut$ = dOut$ + the variables I wanted to log
I found that taking that out reduced the time to 0.0005 seconds.
Wow!

I tested in V2 and it is a little faster, the max time with the concatenated string was 0.09 seconds (still pretty slow) and without it the time was 0.0003 seconds.

So...
Lesson learned!
Use better debugging techniques and don't concatenate strings together to make them so stinking large!

I think I'll be working up a tutorial on a better debug log.
Something that will store debug messages in an array and then output to a file more efficiently with a keystroke.

Anyone interested?

CJB
Valued Member
20
Years of Service
User Offline
Joined: 10th Feb 2004
Location: Essex, UK
Posted: 14th Nov 2014 12:06
Excellent find Naphier! Some experimentation is required to find the most efficient way to append strings. Perhaps Memblocks might be an even more efficient storage medium?
...issues like this often make Tier 2 look attractive!

JimHawkins
15
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 14th Nov 2014 12:38
String concatenation can be slow in any system because a lot of memory allocations may be required. I have a few thoughts about cute tricks in T1, so I'll have a look when I've finished the day job!

-- Jim - When is there going to be a release?
Naphier
14
Years of Service
User Offline
Joined: 2nd Oct 2010
Location: St Petersburg, Florida
Posted: 14th Nov 2014 19:55
Yeah, I was concatenating a string upon itself and 6 str() commands every loop. Didn't really think anything of it, especially that it would slow down the engine that much. But I wanted to let all know so that they can avoid my foolish mistake.

For debug logging I'm probably just going to with a string array, but that won't be all that "easy" code-wise because I don't think I can do an array inside an array. And there's no associative arrays... I can probably do multidimensional, but that would likely be wasting a lot of memory and last time I re-sized multidimensional arrays in 10824 I found that it is a bit unstable.

Typically I log data like you would in a spreadsheet for example:
i, x# , y# , frameTime#, dY#, dX#

But to make a "universal" logger would be easiest to use a a string array. Not a problem to use a single array, or even multiple separate ones.

-------------
Interestingly I just tried the same code using an array for each line of debug output the time went from 0.12 to 0.01 seconds. So about 1/12th of the time. Much more efficient and I can make it even faster since I wouldn't need to concatenate newline all the time. Without that it takes the time down to 0.005. Still 10 times longer than without the strings at all, but not bad. Would probably be even faster if I could do nested arrays or associative arrays, but BASIC is this way for a reason

I have need of this so I'll write up a tutorial on it for this month's newsletter if BatVink has room. In the meantime and T1 suggestions on improving this idea would be very welcome!

Naphier
14
Years of Service
User Offline
Joined: 2nd Oct 2010
Location: St Petersburg, Florida
Posted: 14th Nov 2014 22:41
Well my attempts at a better logging system suck... I'm not doing something right or my initial tests were crap.

I'm now getting slower times when using an array to store the strings vs concatenating the strings. Both are fairly fast. Unfortunately, I'm too busy to look at it much more for the next couple of days, but I'm wondering if someone else can either think of a better way or see what I'm doing wrong.

Main.agc:


logger.agc (method I thought was faster)



debug.agc (method that I thought was slower)
//My current debug function - simple, but very very slow



Thoughts?

Paul Johnston
TGC Developer
22
Years of Service
User Offline
Joined: 16th Nov 2002
Location: United Kingdom
Posted: 15th Nov 2014 00:32
I wouldn't do this

it is moving the entire array to a new memory location every time you resize it, _debug_log$.insert() would be faster as it assumes you're going to be doing lots of inserting and expands the array in chunks to limit the memory allocations. Or just use a really big array and dump it somewhere when you run out of room.

Also opening and closing a file for every debug line is not recommended, I would open the file at the beginning and then close it at the end of the program.
JimHawkins
15
Years of Service
User Offline
Joined: 26th Jul 2009
Location: Hull - UK
Posted: 15th Nov 2014 00:50
Quote: "Also opening and closing a file for every debug line is not recommended"


Certainly not for frame by frame stuff, but if you don't close a file and the program crashes the data will be lost.

-- Jim - When is there going to be a release?
Naphier
14
Years of Service
User Offline
Joined: 2nd Oct 2010
Location: St Petersburg, Florida
Posted: 15th Nov 2014 01:28
Agreed, that's why I'd only WriteDebug() when I needed to actually log stuff, but what I found is that string concatenation on it's own was really slowing the code down, not the code for logging, but the code I have for scrolling which was moving a lot of sprites.
I did a lot of optimization and was benchmarking to logs as I would go to just find out where the bottle neck was. Finally, I wasn't using as few actual commands is would be possible.
The for-next loop was only positioning sprites that would be visible on screen and the time benchmark to do that really hadn't reduced.
Then I went and commented out all of the strings I was concatenating to see if that had any effect (it was the last thing I could do). Indeed it was the bottleneck. 500 iterations of two concatenations of a string was taking a whopping 0.12 seconds on a high level Win 7 PC.

I'm not using insert or anything from v2 yet because it is not ready for production, but it will likely be useful when I'm ready for v2. I was recently told that a v2 tier 1 app was rejected from Apple because of screen freezing on iOS 8. So... until I hear of people using it to successfully publish on iOS I can't really afford to move over to it for anything. But I'm waiting patiently!

Jim hit the nail on the head and that's why I use my original debug log that writes every time. Then if I need to benchmark with it I just concatenate strings until I need to commit them like I'm showing in the examples. There just that many repetitions to get a good average.

Login to post a reply

Server time is: 2024-11-25 11:32:56
Your offset time is: 2024-11-25 11:32:56