api-issue-tracker icon indicating copy to clipboard operation
api-issue-tracker copied to clipboard

Why are Model#find_entity_by_persistent_id and Model#find_entity_by_id so SLOW

Open Fredosixx opened this issue 4 months ago • 4 comments

As I have some doubt in my plugins, I wrote a quick test to measure the performance of these 2 methods, at least on containers:

  • Model#find_entity_by_persistent_id
  • Model#find_entity_by_id

The code for the test is below. It profiles the time taken to retrieve a container from its ID by

  • the native API method
  • versus a brute force method exploring all definitions and trying to find a match of ID among their instances

To run the code, just select an object in the model.

def test_pid_comp
	#Take the selected container in the model
	model = Sketchup.active_model
	comp = model.selection[0]
	return unless comp
	pid_comp = comp.persistent_id
	eid_comp = comp.entityID
	nb_iter = 200
	c = nil
	
	#Method: find_entity_by_persistent_id
	t0 = Time.now
	for i in 0..nb_iter
		c = model.find_entity_by_persistent_id(pid_comp)
	end
	puts "\nfind_entity_by_persistent_id = #{Time.now - t0} s - #{c.persistent_id}"
	
	#Method: Custom method by exploring definition instances for persistence id
	t0 = Time.now
	for i in 0..nb_iter
		model.definitions.each do |cdef|
			c = cdef.instances.find { |c| c.persistent_id == pid_comp }
			break if c
		end
	end
	puts "Custom method PID            = #{Time.now - t0} s - #{c.persistent_id}"

	#Method: find_entity_by_id
	t0 = Time.now
	for i in 0..nb_iter
		c = model.find_entity_by_id(eid_comp)
	end
	puts "\nfind_entity_by_id       = #{Time.now - t0} s - #{c.entityID}"
	
	#Method: Custom method by exploring definition instances for EntityID
	t0 = Time.now
	for i in 0..nb_iter
		model.definitions.each do |cdef|
			c = cdef.instances.find { |c| c.entityID == eid_comp }
			break if c
		end
	end
	puts "Custom method EntityID  = #{Time.now - t0} s - #{c.entityID}"
	
end

The result is (tried 2 times, to show this is consistent) in SU2025:

test_pid_comp

find_entity_by_persistent_id = 2.563366 s - 4734942
Custom method PID            = 1.2880996 s - 4734942

find_entity_by_id       = 2.6136978 s - 808890
Custom method EntityID  = 1.2985735 s - 808890
=> nil


test_pid_comp

find_entity_by_persistent_id = 2.5356326 s - 4734942
Custom method PID            = 1.1624917 s - 4734942

find_entity_by_id       = 2.5597183 s - 808890
Custom method EntityID  = 1.1454812 s - 808890
=> nil

So the native API methods are MORE THAN TWICE SLOWER than a brute force method written in Ruby.

I am surprised, because I thought the API methods were just doing a lookup in an internal table....

To run the test, I took a model in the 3D Warehouse which is not extremely complex (270 containers)

Image Image

Fredosixx avatar Aug 22 '25 13:08 Fredosixx

There is no internal lookup table for IDs or PIDs. It's doing a full model search.

find_entity_by_persistent_id does however have a scope argument that narrow downs what is searched. If you are using PIDs for definitions, have you tested that?

thomthom avatar Aug 27 '25 10:08 thomthom

Unfortunately, there is no filter such as container (or Group and ComponentInstance).

Using the filter entities give the same time:

find_entity_by_persistent_id = 1.19062 s - 3306586
find_entity_by_persistent_id (entities: true) = 1.2159846 s - 3306586
Custom method PID            = 0.9147268 s - 3306586

Fredosixx avatar Aug 28 '25 10:08 Fredosixx

To search a container would need a new option - and it sounds like a very reasonable option to me. It just haven't come up before until now.

I guess it would make sense to add the scope options to find_entities_by_id as well.

thomthom avatar Aug 28 '25 11:08 thomthom

Logged as: SKEXT-4828

sketchup[bot] avatar Sep 01 '25 06:09 sketchup[bot]