[squeak-dev] The Inbox: Graphics-nice.446.mcz
Tom Beckmann
tomjonabc at gmail.com
Sat Feb 20 12:28:48 UTC 2021
Hi Levente, hi Nicolas,
To Levente's comment:
> You left an #asSet send in the above benchmark.
Oups, indeed. But I think the actual measurement was done without the
asSet, I just added it later for experimentation. The numbers appear
consistent when I rerun the lines without #asSet.
After sending the mail, I also realized that the
setOrigin:corner:/merging4: version is of course not legal, since we mutate
the original rectangle that was passed in.
To Nicolas' comment:
> But that's precisely what we try to avoid here: create lots of
> intermediate short-lived objects (Rectangle and Point).
> This is because it may be a performance critical routine.
The most optimized version with the inlined temporaries is a great
implementation but looks like quite a beast to me, which in my opinion
would be sad for something that appears in our standard library. After
looking for senders of Rectangle class>>merging: in my trunk image I only
saw one critical path in recordInvalidRect:, which appears to on average
trigger merging: only once per damaged frame. Is there another use case we
know of?
Best regards,
Tom
On Fri, Feb 19, 2021 at 6:53 PM Levente Uzonyi <leves at caesar.elte.hu> wrote:
> Hi Tom,
>
> On Fri, 19 Feb 2021, Tom Beckmann wrote:
>
> > Hi everyone,
> >
> > just another idea for your consideration:
> >
> > merging3: listOfRects
> > ^ listOfRects reduce: [:a :b |
> > self origin: (a origin min: b origin) corner: (a corner max: b
> corner)]
> >
> > If you care more about performance than idioms (not even sure if this is
> legal):
> > merging4: listOfRects
> > ^ listOfRects reduce: [:a :b |
> > a setOrigin: (a origin min: b origin) corner: (a corner max: b
> corner)]
> >
> > And finally, the, in my opinion, most elegant version. Sadly, it's also
> the slowest.
> > merging5: listOfRects
> > ^ listOfRects reduce: [:a :b | a quickMerge: b]
> >
> >
> >
> > Some unrepresentative benchmarks:
> >
> > " Levente's version from above with temps "
> > [Rectangle merging2: {0 @ 0 extent: 100 @ 100. -20 @ -20 extent: 80 @
> 80. 30 @ 30 extent: 100 @ 100}] bench '3,740,000 per second. 267
> nanoseconds per run. 37.46501 % GC time.'
> > " the 'clean' version "
> > [Rectangle merging3: {0 @ 0 extent: 100 @ 100. -20 @ -20 extent: 80 @
> 80. 30 @ 30 extent: 100 @ 100}] bench '3,020,000 per second. 331
> nanoseconds per run. 40.93181 % GC time.'
> > " the version that mutates rectangles "
> > [Rectangle merging4: {0 @ 0 extent: 100 @ 100. -20 @ -20 extent: 80 @
> 80. 30 @ 30 extent: 100 @ 100} asSet] bench '3,330,000 per second. 300
> nanoseconds per run. 40.53189 % GC time.'
>
> You left an #asSet send in the above benchmark.
>
>
> Levente
>
> > " using quickMerge "
> > [Rectangle merging5: {0 @ 0 extent: 100 @ 100. -20 @ -20 extent: 80 @
> 80. 30 @ 30 extent: 100 @ 100}] bench '2,930,000 per second. 341
> nanoseconds per run. 42.32 % GC time.'
> >
> > Best,
> > Tom
> >
> > On Thu, Feb 18, 2021 at 11:17 PM Levente Uzonyi <leves at caesar.elte.hu>
> wrote:
> > Hi Chris,
> >
> > On Wed, 17 Feb 2021, Chris Muller wrote:
> >
> > > This is what I would do:
> > >
> > > merging: listOfRects
> > > "A number of callers of merge: should use this method."
> > > ^ listOfRects
> > > inject:
> > > (self
> > > origin: Float infinity @ Float infinity
> > > corner: Float infinity negated @ Float infinity
> negated)
> > > into: [ : rect : each | rect quickMerge: each ]
> > >
> > > With #quickMerge:, you're only creating a new Rectangle when it
> needed to grow to accomodate the current element, but many of the elements
> might fit completely, resulting in no additional instantiation. Do an
> > analysis of how
> > > many temporary Point objects we create -- hint: it's a ton --
> and my own attempts to optimize that in my Kml framework were not fruitful
> (e.g., ~1%), with a trade-off of duplicating implementation across
> > multiple methods and
> > > making the system's code harder to read and understand and
> maintain.
> >
> > With my benchmark, your version is slower than the one from 2003,
> > especially when the collection is small. And it doesn't handle the
> case of
> > empty listOfRects the same way: it silently returns a rectangle
> instead of
> > raising an error.
> >
> > Here's the version I came up with the other day:
> >
> >
> > merging: listOfRects
> > "A number of callers of merge: should use this method."
> >
> > | minTopLeftX minTopLeftY maxBottomRightX maxBottomRightY |
> > listOfRects do: [ :rectangle |
> > | topLeft bottomRight |
> > topLeft := rectangle topLeft.
> > bottomRight := rectangle bottomRight.
> > minTopLeftX
> > ifNil: [
> > minTopLeftX := topLeft x.
> > minTopLeftY := topLeft y.
> > maxBottomRightX := bottomRight x.
> > maxBottomRightY := bottomRight y ]
> > ifNotNil: [
> > topLeft x < minTopLeftX ifTrue: [
> minTopLeftX := topLeft x ].
> > topLeft y < minTopLeftY ifTrue: [
> minTopLeftY := topLeft y ].
> > bottomRight x > maxBottomRightX
> ifTrue: [ maxBottomRightX := bottomRight x ].
> > bottomRight y > maxBottomRightY
> ifTrue: [ maxBottomRightY := bottomRight y ] ] ].
> > ^self origin: minTopLeftX @ minTopLeftY corner:
> maxBottomRightX @ maxBottomRightY
> >
> >
> > Levente
> >
> > >
> > > - Chris
> > >
> > >
> > > On Wed, Feb 17, 2021 at 11:27 AM Levente Uzonyi <
> leves at caesar.elte.hu> wrote:
> > > On Wed, 17 Feb 2021, Marcel Taeumel wrote:
> > >
> > > > Hmm... looking at performance ... why not just add
> #asSequenceableCollection, which would only impact Set arguments?
> > >
> > > I don't think we have such method. Adding one would raise
> the usual
> > > question: should it create a new collection or return self
> if self
> > > already to the requested collection kind?
> > > IIRC currently the only outlier is #asOrderedCollection
> which always
> > > creates a copy when the receiver is an OrderedCollection,
> and that
> > > property is being relied on, so it can't be changed...
> > >
> > > > As a programmer, I do not want to choose between #merge:
> and #quickMerge:. Or similar. :-)
> > >
> > > IMO, we simply need one quick solution. If you have a Set,
> you may need
> > > that help from the library even more.
> > > #quickMerge: is only good for merging two rectangles. It
> does not solve
> > > the GC issue #merge: has.
> > >
> > >
> > > Levente
> > >
> > > >
> > > > Best,
> > > > Marcel
> > > >
> > > > Am 13.02.2021 17:05:07 schrieb
> commits at source.squeak.org <commits at source.squeak.org>:
> > > >
> > > > Nicolas Cellier uploaded a new version of Graphics
> to project The Inbox:
> > > >
> http://source.squeak.org/inbox/Graphics-nice.446.mcz
> > > >
> > > > ==================== Summary ====================
> > > >
> > > > Name: Graphics-nice.446
> > > > Author: nice
> > > > Time: 13 February 2021, 5:04:52.453325 pm
> > > > UUID: d13c1db2-370f-4fa6-b7ae-e6766bf0c8fb
> > > > Ancestors: Graphics-dtl.445
> > > >
> > > > Let Rectangle merging:/encompassing: an unordered
> collection.
> > > >
> > > > =============== Diff against Graphics-dtl.445
> ===============
> > > >
> > > > Item was changed:
> > > > ----- Method: Rectangle class>>encompassing: (in
> category 'instance creation') -----
> > > > encompassing: listOfPoints
> > > > "A number of callers of encompass: should use this
> method."
> > > > | topLeft bottomRight |
> > > > + topLeft := bottomRight := listOfPoints anyOne.
> > > > + listOfPoints do:
> > > > - topLeft := bottomRight := listOfPoints first.
> > > > - listOfPoints allButFirstDo:
> > > > [:p |topLeft := topLeft min: p.
> > > > + bottomRight := bottomRight max: p].
> > > > - bottomRight := bottomRight max: p].
> > > > ^self origin: topLeft corner: bottomRight
> > > > !
> > > >
> > > > Item was changed:
> > > > ----- Method: Rectangle class>>merging: (in
> category 'instance creation') -----
> > > > merging: listOfRects
> > > > "A number of callers of merge: should use this
> method."
> > > > + | aRectangle bottomRight topLeft |
> > > > + aRectangle := listOfRects anyOne.
> > > > + topLeft := aRectangle topLeft.
> > > > + bottomRight := aRectangle bottomRight.
> > > > - | bottomRight topLeft |
> > > > - topLeft := listOfRects first topLeft.
> > > > - bottomRight := listOfRects first bottomRight.
> > > > listOfRects
> > > > + do: [:r | topLeft := topLeft min: r topLeft.
> > > > - allButFirstDo: [:r | topLeft := topLeft min: r
> topLeft.
> > > > bottomRight := bottomRight max: r bottomRight].
> > > > ^self origin: topLeft corner: bottomRight.
> > > > !
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20210220/ed1ae49d/attachment.html>
More information about the Squeak-dev
mailing list
|