Notifications
Clear all

[Closed] Optimization ideas needed

Well, here in London it’s a bank holiday (so no work), and it’s pissing down with rain (so no play).

I’ve also been working on a timestamping / benchmarking struct in the past few weeks, so this seemed like a perfect case study opportunity!

The results are actually really interesting but with the concept and data in front of you, perhaps not that surprising.

The good news is that I’ve managed to speed things up 30 times!

Turns out the slowdown IS related caused by the size of the mesh you’re attaching the mesh to, so when in a loop, this has a rather nasty cumulative effect.

Also, the square root DOES turn out (4 times out of 5 anyway) to be the most efficient number to split the loop up into.

Anyway – I put the results up on my blog, so feel free to take a look.

Cheers,
Dave

Hot damn, I love optimised code.

Perhaps we should have a general discussion of what makes things faster/less memory intensive.

2 Replies
(@zeboxx2)
Joined: 11 months ago

Posts: 0

The MaxScript Help file is a good start, then; see the “How to make it faster?” topic %)

(@erilaz)
Joined: 11 months ago

Posts: 0

Oh I’m aware of that, I think it would be interesting if other methods have come up in people’s scripting journeys to expand the manual’s recommendations.

Alright… here’s a few I recall off the top of my head – haven’t dug into my scripts to find old comments on oddball speed-ups.

At one point I needed random point3 integers, lots and lots of them. The problem is, random <point3> <point3> makes the values within those point3s floats.
So…



 startTime = timeStamp()
 for i = 1 to 3000000 do (
 	randP3 = random [0,0,0] [10,10,10]
 	randP3.x = randP3.x as integer
 	randP3.y = randP3.y as integer
 	randP3.z = randP3.z as integer
 )
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 16.854
 
 startTime = timeStamp()
 for i = 1 to 3000000 do (
 	randP3x = random 0 10
 	randP3y = random 0 10
 	randP3z = random 0 10
 	randP3 = [randP3x,randP3y,randP3z]
 )
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 12.629
 

Subtle, but I actually had to generate tens of millions; becomes a little less subtle. This is on a slower machine, though


Here’s another favorite… UI updates. UI updates are slow.
ProgressBars are a very popular method of showing, well, progress. But updating them all the time is slow. Update them only periodically. For example, only if the update would actually show in the progress bar (depending on its width).


 rollout test "test" (
 	progressbar pb_test
 )
 createDialog test
 pb = test.pb_test -- pre-initialize, lest we incur a speedhit for getting it from the rollout all the time.
 
 startTime = timeStamp()
 for i = 1 to 1000000 do (
 	pb.value = (i / 1000000.0) * 100
 )
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 29.012
 
 
 startTime = timeStamp()
 for i = 1 to 1000000 do (
 	if (mod i 7500 == 0) then ( -- 7500 in this case depending on progressbar width of 133px
 		pb.value = (i / 1000000.0) * 100
 	)
 )
pb.value = 100 -- make sure it does read 100% at the end
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 2.043
 
 -- lets' get rid of that mult as well
 startTime = timeStamp()
 for i = 1 to 1000000 do (
 	if (mod i 7500 == 0) then ( -- 7500 in this case depending on progressbar width of 133px
 		pb.value = (i / 10000.0)
 	)
 )
pb.value = 100
format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 1.943
 

Another one, no code for obvious reasons… f you have an intense loop with a lot of if-tests to validate a value; for example to prevent OOB accesses or so, consider try/catch. Typically try/catch is slower than if-tests, but with enough if-tests, try/catch may just win. Pretty rare, and probably not recommended practice; but if you’re going for speed…


An old favorite… always name the objects you create, as max will otherwise waste time trying to find a unique name for the new object (obviously only do this if you have no fear of creating non-unique names). This assumes cloneNodes cannot be used for whatever reason.


 delete objects
 startTime = timeStamp()
 undo off (
 	for i = 1 to 5000 do (
 		newSphere = geoSphere()
 	)
 )
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 time: 60.226
 
 delete objects
 startTime = timeStamp()
 undo off (
 	for i = 1 to 5000 do (
 		newSphere = geoSphere name:("mySphere" + i as string)
 	)
 )
 format "time: %
" ((timeStamp() - startTime) / 1000.0)
 [color=Blue]time: 34.149[color=#fffffe]
 

[/color][/color]

Now that’s what i’m talking about!

Large meshes can get exponentially slower for certain operations. In a script I wrote to export grids from TIN’s using RayMeshGridIntersect, I resorted to splitting up the TIN before doing intersections, which greatly reduced the running time of the script.

When it comes to copying mesh-data, I immediately thought that perhaps it would be faster to use a Trimesh instead of a node, but I’m not sure how that would affect your transforms.

Someone mentioned if-sentences; sometimes it is not convenient to structure your code optimally to minimize if-sentence overhead (like duplicating a lot of similar, large loops for different outcomes). On one such occation I used a function variable with great success. Prepare a number of predefined functions for each outcome and then assign the appropriate one to a variable before you start the loop. Then your loop can handle different cases without any (unnecessary) if-sentences.

Hi everybody…

Thanks so much for following up! I´m monster busy & won´t have time to implement & test before next week as mentioned to Dave in a PM ( anyone interested in optimization should check his blog ), but please let the ideas come rolling… I´m all ears ( but no brains ATM )

If you haven’t already seen from the link above, I’ve updated my TimeStamper struct. It provides a set of useful methods and properties for all things timing, including:

[ul]
[li]basic start / stop / and then print / alert the result[/li][li]multiple starts then print / alert the average / total[/li][li]differences bewteen different TimeStampers (for comparison tasks)[/li][li]full reporting on all timed tasks, including a breakdown on which iterations were fastest, that can be used straight-off-the-bat in Excel (see graph below)[/li][/ul]You can run multiple timers (each stored in a variable), and the base messaging functions print stuff in English, i.e. “Processing ‘Task Name’ took 7.81 seconds”

Here’s the dump of the tests run above, copied to Excel and a graph made on the columns:

The project home page is here: http://www.keyframesandcode.com/code/development/maxscript/time-stamper/

Ideas and suggestions welcome.

Cheers,
Dave

Thought I’d bump this thread just to thank the previous poster(Dave) for the meshop-attach optimisation… from 215seconds down to 1second… quality!

Aw, thanks Patrick, that’s very nice of you!

You rock! I wish i’d seen this earlier today before crashing max a hundred times trying to speed it up!

Page 2 / 2