[Code] Grepping entities
-
Looks like its a bit faster from what I can tell. Here's the test I ran.
Model of 90,090 edges, 35,035 faces, and 4004 groups.
The code:
edges = [] t = Time.now Sketchup.active_model.entities.each do |e| if e.is_a? Sketchup;;Edge edges << e #Optional line end end puts Time.now-t edges = [] t = Time.now edges = Sketchup.active_model.entities.grep(Sketchup;;Edge) puts Time.now-t
The results:
This is the results when the first section of code actually builds an array of edges 0.159 0.048 This is the results when the first section of code does nothing, merely iterates over the entire collection. 0.1 0.05
Anyhow, its at least 2x faster from what I saw. Anyone else?
-
@tig said:
It would need to be something like:
fs=Sketchup.active_model.entities.grep(Sketchup::Face).select{|f|f.material}
to get an array of all faces that have a material assigned to them etc.But then you do a double iteration. I'd think it's be best to do this as:
fs=Sketchup.active_model.entities.select{|f|f.is_a?(Sketchup::Face) && f.material}
That's just one iteration.
-
Test script:
<span class="syntaxdefault"><br />model </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model<br /><br />num_edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">size<br /><br />puts </span><span class="syntaxstring">"=== Select Entities by Type ==="<br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"> #{model.active_entities.length} entities in the active context."<br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"> #{num_edges} edges in the active context."<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #select{} ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">select</span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) }<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #grep ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- for in ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= []<br /> for </span><span class="syntaxdefault">e in model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities<br /> edges </span><span class="syntaxkeyword"><< </span><span class="syntaxdefault">e </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?( </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">end<br /> puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /> </span><span class="syntaxdefault"></span>
Results:
` === Select Entities by Type ===497078 entities in the active context.
474629 edges in the active context.--- #select{} ---
0.452
0.281
0.281
0.281
0.28
0.281
0.28
0.281
0.265
0.281--- #grep ---
0.14
0.156
0.156
0.141
0.14
0.14
0.156
0.156
0.156
0.156--- for in ---
0.297
0.297
0.296
0.281
0.28
0.281
0.281
0.297
0.297
0.296`I'm seeing similar results as Chris - 80%-90% faster with grep when you only need one type of entities.
-
Wow, nice improvement. You should add a link from the Optimizations topic to here.
-
Further test - just to see how select scales with multiple entities:
<span class="syntaxdefault"><br />model </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model<br /><br />num_edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">size<br /><br />puts </span><span class="syntaxstring">"=== Select Entities by Type ==="<br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"> #{model.active_entities.length} entities in the active context."<br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"> #{num_edges} edges in the active context."<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #select{} ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">select</span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) }<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #grep ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- for in ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= []<br /> for </span><span class="syntaxdefault">e in model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities<br /> edges </span><span class="syntaxkeyword"><< </span><span class="syntaxdefault">e </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?( </span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">end<br /> puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #select{} Edge or Face ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">select</span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) || </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">) }<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">puts </span><span class="syntaxstring">"\n--- #select{} Face or Edge ---"<br /></span><span class="syntaxdefault">10.times </span><span class="syntaxkeyword">{<br /> </span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /> t</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">select</span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">) || </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) }<br /> </span><span class="syntaxdefault">puts Time</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">now</span><span class="syntaxkeyword">-</span><span class="syntaxdefault">t<br /></span><span class="syntaxkeyword">}<br /> </span><span class="syntaxdefault"></span>
Results:
` === Select Entities by Type ===497078 entities in the active context.
474629 edges in the active context.--- #select{} ---
0.27
0.27
0.26
0.26
0.26
0.26
0.27
0.27
0.26
0.26--- #grep ---
0.15
0.15
0.15
0.15
0.15
0.15
0.16
0.15
0.16
0.15--- for in ---
0.29
0.28
0.29
0.28
0.28
0.28
0.28
0.28
0.29
0.29--- #select{} Edge or Face ---
0.28
0.28
0.28
0.27
0.29
0.28
0.29
0.28
0.281
0.28--- #select{} Face or Edge ---
0.37
0.37
0.38
0.38
0.38
0.38
0.37
0.37
0.37
0.37` -
Notice when I select Edges and Faces it matters what I test for first. The whole collection of entities is nearly all edges. If I test for them first it's just about as fast as just selecting edges - because of short-circuiting.
But if I test for faces first - which there isn't any of then there's a penalty.
So test for the most likely cause first!
-
@thomthom said:
@tig said:
It would need to be something like:
fs=Sketchup.active_model.entities.grep(Sketchup::Face).select{|f|f.material}
to get an array of all faces that have a material assigned to them etc.But then you do a double iteration. I'd think it's be best to do this as:
fs=Sketchup.active_model.entities.select{|f|f.is_a?(Sketchup::Face) && f.material}
That's just one iteration.
How about this ?
fs=Sketchup.active_model.entities.grep(Sketchup::Face){|f| f.material ? f : nil }.compact
compact
removes thenil
elements afterward. -
Again - a second iteration. Of the result, but none the less - an extra iteration.
What's interesting here is what the performance is.
-
I've looked st a couple of methods in Vertex Tools - where I refactored them to use grep in combo with hashes and I'm getting huge improvements!
-
Glad I got frustrated on Wednesday and started throwing stuff at the wall to see what stuck! Nice benchmarks Thomthom, hope my find can help some folks out!
-
Dan, did you try benchmarking your pattern? It might not have much of a performance hit if you have the extra filtering criteria in the grep block:
@unknownuser said:
Don’t forget the extra processing — a map operation — comes “free” if you provide grep with a block
Enumerating Enumerable: Enumerable#grep : Global Nerdy
Once again, it’s Enumerating Enumerable time! This is the latest in my series of articles where I set out to make better documentation for Ruby’s Enumerable module than Ruby-Doc.org’s. In this installment, I cover the grep method. In case you missed any of the previous articles, they’re listed and linked below: all? any? collect / […]
Global Nerdy (www.globalnerdy.com)
-
@dkendig said:
Dan, did you try benchmarking your pattern?
No, but it can be added to TT's code above if your interested. (As TT said
compact()
needs to re-iterate the array to remove thenil
elements. I tried usingnext
but the block still returns anil
.)And BTW.. I checked the C source for
compact()
which usesdup()
to create a new array, and then callscompact!()
, ie%(#008080)[rb_compact_bang()]
on the C-side, so to save time, this pattern might as well use the "bang" edition of the method, and save the time to create a new array.I'm deep into a Javascript mod for the forums, presently, and not doing much in Ruby.
-
Can you post your result data as well?
-
And what was the comparison code?
-
drawing_ele_test time: 0.00999999046325684, resulted in 1103 elements found
types_test time: 0.00999999046325684, resulted in 1103 elements found
magic_test time: 0.0420000553131104, resulted in 1103 elements found
loop_test time: 0.0190000534057617, resulted in 1103 elements foundthat's my results from the huge one-liner that I copy and pasted for a scene with 13108 total entities. 10,000 edges, 1,000 component instances, 1,000 groups, 1,000 faces. The goal was to find anything that could have a material applied to it, so I wanted to filter out edges.
So actually it appears my test was flawed. I'm adding entities to a hash, and looping through the desired types in the "types_test" results. In the "drawing_ele_test" I am just doing a comparison to see if the type matches one of the types I am looking for. They both end up taking the same exact amount of time, so there's probably a cleaner way to write this, but under the hood both of those tests are essentially doing the same thing.
-
Just ran a benchmark in a scene with 10,000 edges, one component instance, one face, and one group. It appears that grepping specific classes you are interested in, is faster than doing a more general grep and then comparing within the block.
sample code soon to follow
-
actually, here's the benchmark code I ran
class Magic;def initialize(&block) @block=block;end def ===(other) @block.call(other) end end def GetVrayImportantArrayFromGrepDrawingelement(entities) return entities.grep(Sketchup;;Drawingelement){|ent| false == (ent.class == Sketchup;;Edge) ? ent ; nil}.compact end def GetVrayImportantArrayOfTypesFromGrep(entities,typeHash) for curType in typeHash.keys() typeHash[curType] = entities.grep(curType ) end end def GetVrayImportantArrayFromGrepMagic(entities) return entities.grep(Magic.new {|ent| ent if(ent.class == Sketchup;;ComponentInstance or ent.class == Sketchup;;Group or ent.class == Sketchup;;Face)}) end def GetVrayImportantArrayFromLoop(entities) vrayImportant = Array.new() for ent in entities.to_a if ent.class == Sketchup;;Face or ent.class == Sketchup;;ComponentInstance or ent.class == Sketchup;;Group vrayImportant.push(ent) end end return vrayImportant end def RunBenchmarkOnEntities(entities) testHash = Hash.new() testHash[Sketchup;;Face] = [] testHash[Sketchup;;ComponentInstance] = [] testHash[Sketchup;;Group] = [] grep_drawing_ele_result = grep_magic_result = compare_loop_result = nil grep_drawing_ele_start_time = Time.now.to_f grep_drawing_ele_result = GetVrayImportantArrayFromGrepDrawingelement(entities) grep_drawing_ele_end_time = Time.now.to_f grep_types_start_time = Time.now.to_f grep_types_result = GetVrayImportantArrayOfTypesFromGrep(entities,testHash) grep_types_end_time = Time.now.to_f grep_magic_start_time = Time.now.to_f grep_magic_result = GetVrayImportantArrayFromGrepMagic(entities) grep_magic_end_time = Time.now.to_f compare_loop_start_time = Time.now.to_f compare_loop_result = GetVrayImportantArrayFromLoop(entities) compare_loop_end_time = Time.now.to_f puts "drawing_ele_test time; #{grep_drawing_ele_end_time - grep_drawing_ele_start_time}, resulted in #{grep_drawing_ele_result.size} elements found" puts "types_test time; #{grep_types_end_time - grep_types_start_time}, resulted in #{testHash.values.flatten.size} elements found" puts "magic_test time; #{grep_magic_end_time - grep_magic_start_time}, resulted in #{compare_loop_result.size} elements found" puts "loop_test time; #{compare_loop_end_time - compare_loop_start_time}, resulted in #{compare_loop_result.size} elements found" return nil end RunBenchmarkOnEntities(Sketchup.active_model.entities)
Advertisement