pharo-graphics / Toplo

A widget framework on top of Bloc
MIT License
17 stars 8 forks source link

Is list selection model too slow? #127

Open tinchodias opened 3 months ago

tinchodias commented 3 months ago

More than a second (MacBook Pro 2018) in selecting and deselecting 10000 items:

[| itemCount indices model |
itemCount := 10000.
indices := (1 to: itemCount) shuffled.
model := ToBasicListSelectionModel new.
indices do: [ :each | model selectIndex: each ].
indices do: [ :each | model deselectIndex: each ]] timeToRun asMilliSeconds  "1236"

However, this should be reported in Bloc repo: I profiled it and the main bottleneck is BlSelectionTree>>findOverlappingNeighbours: (belongs to Bloc project).

Screenshot 2024-03-20 at 18 28 27
tinchodias commented 3 months ago

As a very raw reference, simulating adding and removing the indices to a sorted list was 381ms:

[| itemCount indices model |
itemCount := 10000.
indices := (1 to: itemCount) shuffled.
selection := SortedCollection new.
indices do: [ :each | selection add: each ].
indices do: [ :each | selection remove: each ].
] timeToRun asMilliSeconds. "381"

And if sort was done only once at the end of selection, 43ms:

[| itemCount model sorted |
itemCount := 10000.
selection := OrderedCollection new.
indices do: [ :each | selection add: each ].
sorted := selection sorted.
indices do: [ :each | selection remove: each ].
] timeToRun asMilliSeconds.  "43"

But: I didn't analyse well the requirements of the API / invariants of Bloc selection to know if these examples are relevant as comparisions

tinchodias commented 3 months ago

In addition, we can analyse model's containsIndex::

itemCount := 10000.
indices := (1 to: itemCount) shuffled first: itemCount // 1.5.

" Model "
model := ToBasicListSelectionModel new.
indices do: [ :each | model selectIndex: each ].
[
    (1 to: itemCount) collect: [ :each | model containsIndex: each ].
] bench.
 "234 iterations in 5 seconds 7 milliseconds. 46.735 per second"

" Raw equivalent "
selection := Set new.
indices do: [ :each | selection add: each ].
[
    (1 to: itemCount) collect: [ :each | set includes: each ]
] bench.
 "6,484 iterations in 5 seconds 2 milliseconds. 1296.281 per second"

So, 46 executions per second in the model versus 1296 per second in a IdentitySet.

plantec commented 3 months ago

yes, I've already observed the gain with identityDictionary. I've kept the BlMultipleSelection because of the interval selection feature. select:to: deselect:to, selectAll deselectAll

tinchodias commented 3 months ago

For the record: the original motivation for this issue was the output of profiling ToListElementStresser runInSDL, which showed around 46% of the time spent in selection