Thursday, July 7, 2011

The go_faster Parameter



So I've been sitting in on a lot of product demos recently from some great Ruby API developers, and in a couple of cases they did not know about the "go_faster" parameter.

The "go_faster" parameter, you say. What's that?!

Let's look at two pieces of code. First without it:


start_time = Time.new
Sketchup.active_model.start_operation("Draw a grid")
for x in 0..50
for y in 0..50
p1 = [x, y]
p2 = [x+1, y]
p3 = [x+1, y+1]
p4 = [x, y+1]
Sketchup.active_model.entities.add_face(p1, p2, p3, p4);
end
end
Sketchup.active_model.commit_operation
end_time = Time.new
total_time = end_time - start_time
puts total_time.to_s + " seconds to run"


On my IBM Thinkpad this executes in 5.9 seconds. Now let's add the parameter...


start_time = Time.new
Sketchup.active_model.start_operation("Draw a grid", true)
for x in 0..50
for y in 0..50
p1 = [x, y]
p2 = [x+1, y]
p3 = [x+1, y+1]
p4 = [x, y+1]
Sketchup.active_model.entities.add_face(p1, p2, p3, p4);
end
end
Sketchup.active_model.commit_operation
end_time = Time.new
total_time = end_time - start_time
puts total_time.to_s + " seconds to run"


Whoohoo! One little flag and now it runs in 4.7 seconds. That's a 25% increase in performance for typing six keys on my keyboard.

If you're already using Model.start_operation in your plugins, this is a change worth making. If you're not, you should be. In addition to this performance increase, start_operation groups all of your model changes into a single "undo," which makes your plugin easier on your users.

What Ruby performance secrets do you know? Let's hear 'em in the comments!

4 comments:

TIG said...

This is a common 'second argument' in most well written [recent] scripts, however, it will cause a crash in pre-v7 Sketchup versions so, I suggest this version that works in any Sketchup version...

begin
Sketchup.active_model.start_operation("Draw a grid", true)
rescue
Sketchup.active_model.start_operation("Draw a grid")
end

Thomas Thomassen said...

A BIG performance saver is not ever using entity.typename to identify an entity's type. It's horribly slow and the API docs use it in an unfortunate number of examples which is why I suspect it's such a widespread performance issue in a number of plugins I've seen.

Other performance improvements is making use of bulk methods. For instance, don't use selection.add/remove/toggle inside a loop. Cache the entities in an array and use that after you're done looping. Ditto for transforming entities.

There is a long thread at SCF in regard for performance: http://forums.sketchucation.com/viewtopic.php?f=180&t=25305

Scott Lininger said...

Great point, TIG. Thanks for the backward-compatibility reminder.

Thomas Thomassen said...

One of the really big time wasters is using entity.typename - using that to check for types mean you do a string comparison which is dead slow. Checking the class by using .is_a? is many many times faster.

The API docs really should purge all examples using .typename because it's promoting a very bad example which I have seen used many times by plugin authors.

There is a thread dedicated to optimization over at SCF: http://forums.sketchucation.com/viewtopic.php?f=180&t=25305