Valloud Andres Andres.Valloud@oya.state.or.us wrote: Quantify the usefulness of your expectations.
OK: it makes the specification 50% shorter.
Please provide real life examples where x removeAll: x is used as an intention revealing feature in a dialect-independent manner.
Now *there's* a ploy! When someone says there is a bug, demand that he demonstrate that it already possible to use the method across implementations without running into the bug.
Of *course* I can't do that, because there is a bug. The only I could *possibly* provide any real life example of x removeAll: x being used 'in a dialect-independent manner' would be if no Smalltalk had the bug, in which case we wouldn't be having this discussion!
With a start like that, I don't think I need to respond to anything else in that message. But I will.
The standard also says the argument is to be uncaptured, which is defined as meaning the receiver doesn't acquire direct or indirect references to it. I think the spirit of this was "leave the argument alone".
Well, no. If you are going to leave the argument alone, why pass it? If you send even one message to the argument, you are no longer in control of whether the argument will be changed or not.
The spirit of "uncaptured" is precisely "The receiver doesn't REMEMBER the argument afterwards." Anything beyond that is ungrounded in the standard and has to be justified on a case-specific basis.
Saying "the result is undefined when argument==receiver" also coincides with the "leave the argument alone" attitude. Except that you _can't_ leave the argument alone. You have to send it messages to find out what its elements are. It is possible to construct collections where asking the question changes the answer. (Not very sensible ones, granted. But if other people may imagine hypothetical collection classes that would break things, so may I.)
IF the argument is to be left alone, then of course it is to be left alone. But the ANSI standard does NOT say that the argument is to be left alone.
This is actually an interesting point, which should be considered in a future revision of the ANSI standard. None of the #removeAll: methods actually say _how_ the elements are to be determined. There is no limit whatsoever placed on which messages may be sent to the argument.
It is at least arguable that an implementation which removed the elements from the argument one by one could conform, as long as it put them back afterwards (if that didn't end up changing the receiver). The standard very carefully describes the effect on the receiver _without_ saying anything about how it is to be done. (Even the 'as if ... remove:' stuff doesn't mean you have to send #remove:, because that only applies to specific cases where the effect of #remove: is also specified.) We really cannot conclude from the text of the standard as we have it that no #remove: messages may be sent to the argument.
At any rate, the standard does NOT say that #do: may be sent to the argument or that #copy may not be. The implementation
aCollection copy do: [:each | self remove: each ifAbsent: [self errorNotFound]]
fully conforms to everything the standard says, is at least in the cases I measured, faster than the existing implementation, and does not have the hole in its coverage.
The ANSI standard isn't written in stone.
No, until it is revised it is rather less mutable than that.
I'd rather amend the standard than agreeing with it regardless of the cost. Nobody is suggesting 'regardless of the cost'.
I have suggested many ways of getting the effect I want, and Allen Wirfs-Brock, while pointing out that the committee didn't think about the problem, did say that mine was a _possible_ reading of the standard. The outcome is that in this case, conforming to the letter of the standard, including NOT having a hole in the domain, could give us a *FASTER* implementation than what we have now with an interface which is *EASIER* to understand.
It is the people who are insisting on not making this correction who are demanding something costly, in my view.
By the way, if there _is_ a process for amending the Smalltalk standard, I am very pleased to hear it. Who do I write to? What is the process?
On Thursday, August 29, 2002, at 02:30 AM, Richard A. O'Keefe wrote:
Now *there's* a ploy! When someone says there is a bug, demand that he demonstrate that it already possible to use the method across implementations without running into the bug.
Assuming without further argument that there is a bug, this argument simply restates its conclusion and devolves, therefore, into sophistry.
Richard,
By the way, if there _is_ a process for amending the Smalltalk standard, I am very pleased to hear it. Who do I write to? What is the process?
If you propose a change here, could you make sure that the following code also works?
| c | c := #(1 2 3) asOrderedCollection. c removeAll: c readStream.
Wim Boot
Wim Boot wrote:
Richard,
By the way, if there _is_ a process for amending the Smalltalk standard, I am very pleased to hear it. Who do I write to? What is the process?
If you propose a change here, could you make sure that the following code also works?
| c | c := #(1 2 3) asOrderedCollection. c removeAll: c readStream.
Wim Boot
It works in my little CS (with one tiny change). Is there any guide as to when to use (recv asFoo) or (recv as: Foo)?
The one thing that's missing is the exception for when the removal set has an element not in #removeAll:'s reciever.
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 1 September 2002 at 5:04:54 pm'!
!OrderedCollection methodsFor: 'adding' stamp: 'bmk 9/1/2002 00:57'! truncate:aSize aSize > self size ifTrue:[ self error: 'ENOTPOSIX'] ifFalse:[lastIndex := firstIndex+aSize-1]! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 17:04'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. 1 to: self size do:[:index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel ]. ]. self squeegee:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 01:00'! squeegee: sentinel "remove all instances of the sentinel, and squish down the array" |tightIndex| tightIndex := 1. 1 to: self size do: [:fluffedIndex| "probably safer to manually iterate here than trust #do:" (self at: fluffedIndex) == sentinel ifFalse:[ self at:tightIndex put: (self at:fluffedIndex). tightIndex := tightIndex+1. ]. ]. self truncate:tightIndex -1 ! !
Just one last nit to fix with my little exercise of "what would a programming Pooh Bear do?"
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 5 September 2002 at 5:15:33 pm'!
!OrderedCollection methodsFor: 'adding' stamp: 'bmk 9/5/2002 15:45'! truncate:aSize |newLastIndex| aSize > self size ifTrue:[ self error: 'cannot truncate larger'] ifFalse:[ newLastIndex := firstIndex+aSize-1. newLastIndex+1 to: lastIndex do: [:position| array at: position put: nil]. lastIndex := newLastIndex]! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 17:04'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. 1 to: self size do:[:index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel ]. ]. self squeegee:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/5/2002 15:47'! squeegee: sentinel "remove all instances of the sentinel, and squish down the array" |tightIndex| tightIndex := firstIndex. 1 to: self size do: [:fluffedIndex| "probably safer to manually iterate here than trust #do:" (self at: fluffedIndex) == sentinel ifFalse:[ self at:tightIndex put: (self at:fluffedIndex). tightIndex := tightIndex+1. ]. ]. self truncate:tightIndex -1 ! !
This is definitely the last oopsie. Now it should work if the OrderedCollection has slack.
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 5 September 2002 at 7:18:39 pm'!
!OrderedCollection methodsFor: 'adding' stamp: 'bmk 9/5/2002 15:45'! truncate:aSize |newLastIndex| aSize > self size ifTrue:[ self error: 'cannot truncate larger'] ifFalse:[ newLastIndex := firstIndex+aSize-1. newLastIndex+1 to: lastIndex do: [:position| array at: position put: nil]. lastIndex := newLastIndex]! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 17:04'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. 1 to: self size do:[:index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel ]. ]. self squeegee:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/5/2002 19:16'! squeegee: sentinel "remove all instances of the sentinel, and squish down the array" |tightIndex| tightIndex := firstIndex. 1 to: self size do: [:fluffedIndex| "probably safer to manually iterate here than trust #do:" (self at: fluffedIndex) == sentinel ifFalse:[ self at:tightIndex put: (self at:fluffedIndex). tightIndex := tightIndex+1. ]. ]. self truncate:tightIndex -firstIndex ! !
For the love of traffic, here is another exciting release. Now removeAll: provides even more exciting features, like not breaking image saving. I swear, this is just 2 versions away from MilSpec.
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 5 September 2002 at 8:06:36 pm'!
!OrderedCollection methodsFor: 'adding' stamp: 'bmk 9/5/2002 15:45'! truncate:aSize |newLastIndex| aSize > self size ifTrue:[ self error: 'cannot truncate larger'] ifFalse:[ newLastIndex := firstIndex+aSize-1. newLastIndex+1 to: lastIndex do: [:position| array at: position put: nil]. lastIndex := newLastIndex]! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 17:04'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. 1 to: self size do:[:index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel ]. ]. self squeegee:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/5/2002 20:03'! squeegee: sentinel "remove all instances of the sentinel, and squish down the array." |tightIndex| tightIndex := 1. 1 to: self size do: [:fluffedIndex| "probably safer to manually iterate here than trust #do:" (self at: fluffedIndex) == sentinel ifFalse:[ self at:tightIndex put: (self at:fluffedIndex). tightIndex := tightIndex+1. ]. ]. self truncate:tightIndex - 1 ! !
Brian,
If i still can read this last version reintroduces the slack problem?! One more point: do you really think dowithindex would be so problematic?
Just my two cents, Torge
Brian Keefer wrote:
For the love of traffic, here is another exciting release. Now removeAll: provides even more exciting features, like not breaking image saving. I swear, this is just 2 versions away from MilSpec.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 5 September 2002 at 8:06:36 pm'!
!OrderedCollection methodsFor: 'adding' stamp: 'bmk 9/5/2002 15:45'! truncate:aSize |newLastIndex| aSize > self size ifTrue:[ self error: 'cannot truncate larger'] ifFalse:[ newLastIndex := firstIndex+aSize-1. newLastIndex+1 to: lastIndex do: [:position| array at: position put: nil]. lastIndex := newLastIndex]! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/1/2002 17:04'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. 1 to: self size do:[:index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel ]. ]. self squeegee:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/5/2002 20:03'! squeegee: sentinel "remove all instances of the sentinel, and squish down the array." |tightIndex| tightIndex := 1. 1 to: self size do: [:fluffedIndex| "probably safer to manually iterate here than trust #do:" (self at: fluffedIndex) == sentinel ifFalse:[ self at:tightIndex put: (self at:fluffedIndex). tightIndex := tightIndex+1. ]. ]. self truncate:tightIndex - 1 ! !
Torge Husfeldt wrote:
Brian,
If i still can read this last version reintroduces the slack problem?! One more point: do you really think dowithindex would be so problematic?
The head slack is left alone (in 4.cs) by using OrderedCollection's normal access methods (self at:). In the .3.cs, I was *thinking* about manipulating the array instvar directly, and that resulted in a muddled #truncate:. Man, that was full of stupid.
Bonus chocolate goes to whoever can find a way to 1.) Maintain the approximate head/tail slack ratio 2.) without extra passes through the array (or other untowardly overhead).
I specifically avoided #doWithIndex: because I never heard of it. It was slightly easier to use #to:do: than look up a replacement.
This version (too many versions for such a simple thing!) follows the fixes reccommended by Mr. O'Keefe. I'm even going along with the #= sentinel comparison in removeOccurancesOf:.
On a completely different matter, is Object>>hash safe? It seems to use the OOP address (as in a C pointer), which could change with each incremental GC.
'From Squeak3.2gamma of 15 January 2002 [latest update: #4881] on 6 September 2002 at 11:11:08 pm'!
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/6/2002 23:10'! removeAll: aCollection |removalSet sentinel|
removalSet := aCollection as: Bag. "#asBag is unfriendly to streams" sentinel := Object new. self withIndexDo: [:value :index| (removalSet includes:(self at:index)) ifTrue:[ self at:index put:sentinel. ]. ]. self removeOccurancesOf:sentinel. ^aCollection. "don't know why. Nobody wants it"! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/6/2002 23:10'! removeOccurancesOf: sentinel "Though this was made with consideration towards sentinels, any regular container member could be sent. It just reads better using the name sentinel than anItem. What would ``valueOrAnItem'' mean?"
|valuesOnlyIndex| valuesOnlyIndex := 1. self withIndexDo: [:valueOrSentinel :valuesOrSentinelsIndex| "VOSIndex unnecessary" sentinel = valueOrSentinel ifFalse:[ "As long as sentinel class -> Object, #= means #==." self at:valuesOnlyIndex put: valueOrSentinel. valuesOnlyIndex := valuesOnlyIndex + 1. ]. ]. self truncate:valuesOnlyIndex - 1 ! !
!OrderedCollection methodsFor: 'removing' stamp: 'bmk 9/5/2002 15:45'! truncate:aSize |newLastIndex| aSize > self size ifTrue:[ self error: 'cannot truncate larger'] ifFalse:[ newLastIndex := firstIndex+aSize-1. newLastIndex+1 to: lastIndex do: [:position| array at: position put: nil]. lastIndex := newLastIndex]! !
I've noticed that changing classes in the Browser is sluggish. (Squeak 3.2g, #4956, Win2000, p3-600). If I have the category 'Morphic-Kernel' open, selecting 'Morph' requires about one second. Presumably, it is unusally bad because of the high number of messages for this class. I tried this on another (133 mhz) machine, and selecting 'Morph' required 4 to 5 seconds; in addition, many other classes are slow enough to be objectionable. We should be able to do better than this, right? On the slow machine, the MVC browser was much faster (<500 ms).
I did a message tally while clicking between 'Morph' and 'HandMorph' repeatedly, which you can see below. It looks like most of the time is being spent populating PluggableListMorphs with items. I think the problem must be at or below: -- 55.6% {11800ms} PluggableMessageCategoryListMorph(PluggableListMorph)>>list:
I don't really understand whats going on beyond this point. It looks like a lot of time is being spend recording damage and fiddling with bounds during the list population. There are also tons of fullbounds and changed messages which would seem to be unnecessary during the construction phase. Just for fun, I removed the call to 'TransformMorph(Morph)>>addedOrRemovedSubmorph'. Nothing bad happened (immediately, anyway) and it was noticeably faster. (Thats probably a bad idea - I was just messing around).
If anyone could point me in the right direction, or point out my fallacies, that would be great.
Thanks, Eddie
- 1312 tallies, 21223 msec.
**Tree** 99.9% {21202ms} PasteUpMorph>>doOneCycle 99.8% {21181ms} WorldState>>doOneCycleFor: 78.2% {16596ms} WorldState>>doOneCycleNowFor: |62.9% {13349ms} HandMorph>>processEvents | |62.7% {13307ms} HandMorph>>handleEvent: | | 61.4% {13031ms} HandMorph>>sendMouseEvent: | | 61.4% {13031ms} HandMorph>>sendEvent:focus:clear: | | 60.1% {12755ms} HandMorph>>sendFocusEvent:to:clear: | | 60.1% {12755ms} PluggableListMorph(Morph)>>handleFocusEvent: | | 60.1% {12755ms} PluggableListMorph(Morph)>>handleEvent: | | 60.1% {12755ms} MouseButtonEvent>>sentTo: | | 60.1% {12755ms} PluggableListMorph(Morph)>>handleMouseUp: | | 60.1% {12755ms} PluggableListMorph>>mouseUp: | | 60.1% {12755ms} PluggableListMorph>>setSelectedMorph: | | 60.1% {12755ms} PluggableListMorph>>changeModelSelection: | | 60.1% {12755ms} Browser>>classListIndex: | | 58.7% {12458ms} Browser(Object)>>changed: | | 58.2% {12352ms} PluggableMessageCategoryListMorph(PluggableListMorph)>>update: | | 55.6% {11800ms} PluggableMessageCategoryListMorph(PluggableListMorph)>>list: | | |30.3% {6431ms} TransformMorph(Morph)>>addAllMorphs: | | | |29.1% {6176ms} TransformMorph(Morph)>>addedOrRemovedSubmorph: | | | | 21.5% {4563ms} StringMorph(Morph)>>changed | | | | |21.0% {4457ms} StringMorph(Morph)>>invalidRect: | | | | | 21.0% {4457ms} StringMorph(Morph)>>invalidRect:from: | | | | | 20.9% {4436ms} TransformMorph>>invalidRect:from: | | | | | 12.5% {2653ms} TransformMorph(Morph)>>invalidRect:from: | | | | | |12.2% {2589ms} PluggableMessageCategoryListMorph(Morph)>>invalidRect:from: | | | | | | 10.9% {2313ms} SystemWindow(Morph)>>invalidRect:from: | | | | | | 8.9% {1889ms} PasteUpMorph>>invalidRect:from: [7.7% {1634ms} WorldState>>recordDamagedRect: [ 7.6% {1613ms} DamageRecorder>>recordInvalidRect: [ 3.7% {785ms} Rectangle>>intersect: [ |3.1% {658ms} Rectangle class>>origin:corner: [ 2.2% {467ms} Rectangle>>area | | | | | 6.5% {1379ms} MorphicTransform(DisplayTransform)>>localBoundsToGlobal: | | | | | 3.0% {637ms} MorphicTransform(DisplayTransform)>>localPointsToGlobal: | | | | | |2.1% {446ms} MorphicTransform>>localPointToGlobal: | | | | | 2.5% {531ms} Rectangle class>>encompassing: | | | | 7.5% {1592ms} StringMorph>>fullBounds | | | | 7.5% {1592ms} StringMorph(Morph)>>fullBounds | | | | 6.6% {1401ms} StringMorph(Morph)>>layoutBounds | | | | 5.9% {1252ms} StringMorph(Morph)>>innerBounds | | | | 4.0% {849ms} Rectangle>>insetBy: | | | | 3.3% {700ms} Rectangle class>>origin:corner: | | | | 2.4% {509ms} Rectangle>>setOrigin:corner: | | |11.5% {2441ms} StringMorph(Morph)>>bounds: | | | |7.7% {1634ms} StringMorph(Morph)>>position: | | | | |4.4% {934ms} StringMorph>>fullBounds | | | | | 4.0% {849ms} StringMorph(Morph)>>fullBounds | | | | | 3.2% {679ms} StringMorph(Morph)>>layoutBounds | | | | | 2.7% {573ms} StringMorph(Morph)>>innerBounds | | | |3.4% {722ms} StringMorph(Morph)>>extent: | | |5.9% {1252ms} PluggableListMorph(ScrollPane)>>setScrollDeltas | | | |2.8% {594ms} PluggableListMorph(ScrollPane)>>leftoverScrollRange | | |3.8% {806ms} StringMorph class>>contents:font: | | | 3.7% {785ms} StringMorph>>initWithContents:font:emphasis: | | | 3.2% {679ms} StringMorph>>contents: | | | 3.0% {637ms} StringMorph>>fitContents | | 2.4% {509ms} PluggableListMorph>>getList | | 2.4% {509ms} Browser>>messageList | | 2.4% {509ms} ClassOrganizer>>allMethodSelectors | | 2.4% {509ms} Array(ArrayedCollection)>>sort |9.3% {1974ms} WorldState>>displayWorldSafely: | |9.0% {1910ms} PasteUpMorph>>displayWorld | | 9.0% {1910ms} PasteUpMorph>>privateOuterDisplayWorld | | 9.0% {1910ms} WorldState>>displayWorld:submorphs: | | 7.6% {1613ms} WorldState>>drawWorld:submorphs:invalidAreasOn: | | 7.2% {1528ms} FormCanvas(Canvas)>>fullDrawMorph: | | 7.2% {1528ms} FormCanvas(Canvas)>>fullDraw: | | 7.2% {1528ms} SystemWindow(Morph)>>fullDrawOn: | | 6.6% {1401ms} SystemWindow(Morph)>>drawSubmorphsOn: | | 6.6% {1401ms} FormCanvas(Canvas)>>fullDrawMorph: | | 6.6% {1401ms} FormCanvas(Canvas)>>fullDraw: | | 6.6% {1401ms} AlignmentMorph(Morph)>>fullDrawOn: | | 5.9% {1252ms} AlignmentMorph(Morph)>>drawSubmorphsOn: | | 5.9% {1252ms} FormCanvas(Canvas)>>fullDrawMorph: | | 5.8% {1231ms} FormCanvas(Canvas)>>fullDraw: | | 5.8% {1231ms} PluggableListMorph(Morph)>>fullDrawOn: | | 3.6% {764ms} PluggableListMorph(Morph)>>drawSubmorphsOn: | | 3.5% {743ms} FormCanvas(Canvas)>>fullDrawMorph: | | 3.5% {743ms} FormCanvas(Canvas)>>fullDraw: | | 3.5% {743ms} ScrollBar(Morph)>>fullDrawOn: |6.0% {1273ms} PasteUpMorph>>runStepMethods | 6.0% {1273ms} WorldState>>runStepMethodsIn: | 6.0% {1273ms} WorldState>>runLocalStepMethodsIn: | 5.5% {1167ms} StepMessage(MorphicAlarm)>>value: | 5.4% {1146ms} SystemWindow>>stepAt: | 5.4% {1146ms} Browser(Object)>>stepAt:in: | 5.4% {1146ms} Browser(CodeHolder)>>stepIn: | 5.4% {1146ms} Browser(CodeHolder)>>updateListsAndCodeIn: | 5.1% {1082ms} Browser(Object)>>updateListsAndCodeIn: | 5.1% {1082ms} PluggableListMorph>>verifyContents | 5.0% {1061ms} PluggableListMorph>>getList | 5.0% {1061ms} Browser>>messageList | 5.0% {1061ms} ClassOrganizer>>allMethodSelectors | 5.0% {1061ms} Array(ArrayedCollection)>>sort | 4.1% {870ms} Array(ArrayedCollection)>>sort: | 4.1% {870ms} Array(ArrayedCollection)>>mergeSortFrom:to:by: | 2.4% {509ms} primitives 21.4% {4542ms} WorldState>>interCyclePause: 21.3% {4520ms} Delay>>wait 21.3% {4520ms} primitives **Leaves** 21.3% {4520ms} Delay>>wait 7.8% {1655ms} Rectangle class>>origin:corner: 7.1% {1507ms} Rectangle>>setOrigin:corner: 3.1% {658ms} Array(ArrayedCollection)>>mergeFirst:middle:last:into:by: 3.1% {658ms} SystemWindow(Morph)>>valueOfProperty:ifAbsent: 2.9% {615ms} Array(SequenceableCollection)>>do: 2.8% {594ms} Point>>+ 2.4% {509ms} Array(ArrayedCollection)>>mergeSortFrom:to:by:
**Memory** old -721,452 bytes young +157,612 bytes used -563,840 bytes free +3,386,224 bytes
**GCs** full 1 totalling 497ms (2.0% uptime), avg 497.0ms incr 2214 totalling 2,769ms (13.0% uptime), avg 1.0ms tenures 51 (avg 43 GCs/tenure) root table 0 overflows
"Eddie Cottongim" cottonsqueak@earthlink.net wrote:
I did a message tally while clicking between 'Morph' and 'HandMorph' repeatedly, which you can see below. It looks like most of the time is being spent populating PluggableListMorphs with items. I think the problem must be at or below: -- 55.6% {11800ms} PluggableMessageCategoryListMorph(PluggableListMorph)>>list:
Ah, if it's the UI bogging down on large lists, then my LargeLists patch might fix this up.... It avoids calculating string sizes for all of the entries in the list. You just load the patch and get this benefit -- no tweaking of Browser is necessary. (LargeLists also has an alternative way to specify the strings; the model can supply individual elements instead of having to supply the entire list. This is a big saving in Celeste, where even *calculating* the lines is expensive.)
Okay, with LargeLists, it still seems It still seems a little sluggish to me, but it no longer matters how many items are in the list. Morph and HandMorphForReplay are selected equally fast.
-Lex
==== selecting Morph and HandMorphForReplay under LargeLists =====
- 2014 tallies, 34913 msec.
**Tree** 100.0% {34913ms} PasteUpMorph>>doOneCycle 100.0% {34913ms} WorldState>>doOneCycleFor: 92.9% {32434ms} WorldState>>doOneCycleNowFor: |89.3% {31177ms} HandMorph>>processEvents | 89.1% {31107ms} HandMorph>>handleEvent: | 87.3% {30479ms} HandMorph>>sendKeyboardEvent: | 87.3% {30479ms} HandMorph>>sendEvent:focus:clear: | 87.3% {30479ms} HandMorph>>sendFocusEvent:to:clear: | 87.3% {30479ms} PluggableListMorph(Morph)>>handleFocusEvent: | 87.3% {30479ms} PluggableListMorph(Morph)>>handleEvent: | 87.3% {30479ms} KeyboardEvent>>sentTo: | 87.3% {30479ms} PluggableListMorph(Morph)>>handleKeystroke: | 87.3% {30479ms} PluggableListMorph>>keyStroke: | 87.3% {30479ms} PluggableListMorph>>specialKeyPressed: | 86.7% {30270ms} PluggableListMorph>>changeModelSelection: | 86.7% {30270ms} Browser>>classListIndex: | 42.9% {14978ms} Browser(Object)>>changed: [21.9% {7646ms} SystemWindow>>update: [ |21.4% {7471ms} Browser>>labelString [ | 21.4% {7471ms} Browser>>selectedClass [ | 19.8% {6913ms} VirtualRootModule>>allDefinitionsFor:onlyExported:detect: [ | 18.0% {6284ms} VirtualRootModule(Module)>>deepSubAndDeltaModules [ | 14.2% {4958ms} Module>>deltaModules [ | |9.6% {3352ms} Module>>neighborModules [ | | |8.8% {3072ms} Array(Collection)>>select:thenCollect: [ | | | 6.8% {2374ms} Array(SequenceableCollection)>>select: [ | | | 2.7% {943ms} Array(SequenceableCollection)>>at: [ | | | 2.1% {733ms} primitives [ | |4.4% {1536ms} Array(SequenceableCollection)>>select: [ | 2.9% {1012ms} VirtualRootModule(Module)>>deepSubmodulesDo: [ | 2.9% {1012ms} Module>>deepSubmodulesDo: [ | 2.7% {943ms} Module>>deepSubmodulesDo: [ | 2.5% {873ms} Module>>deepSubmodulesDo: [20.8% {7262ms} PluggableListMorph>>update: [ 20.1% {7018ms} PluggableListMorph>>updateList [ 9.7% {3387ms} LazyListMorph>>listChanged [ |9.4% {3282ms} LazyListMorph>>getListSize [ | 9.4% {3282ms} PluggableListMorph>>getListSize [ | 9.4% {3282ms} PluggableListMorph>>getList [ | 8.8% {3072ms} Browser>>messageList [ | 8.8% {3072ms} ClassOrganizer>>allMethodSelectors [ | 8.8% {3072ms} Array(ArrayedCollection)>>sort [ | 5.1% {1781ms} Array(ArrayedCollection)>>sort: [ | |5.1% {1781ms} Array(ArrayedCollection)>>mergeSortFrom:to:by: [ | | 5.1% {1781ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | | 4.7% {1641ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | | 4.3% {1501ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | | 3.7% {1292ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | | 3.2% {1117ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | | 2.7% {943ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [[2.1% {733ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 2.3% {803ms} Symbol(String)>><= [ 9.6% {3352ms} PluggableListMorph>>selectionIndex: [ 9.5% {3317ms} PluggableListMorph>>getListSize [ 9.5% {3317ms} PluggableListMorph>>getList [ 9.2% {3212ms} Browser>>messageList [ 9.0% {3142ms} ClassOrganizer>>allMethodSelectors [ 9.0% {3142ms} Array(ArrayedCollection)>>sort [ 5.6% {1955ms} Array(ArrayedCollection)>>sort: [ |5.6% {1955ms} Array(ArrayedCollection)>>mergeSortFrom:to:by: [ | 5.6% {1955ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 5.2% {1815ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 4.6% {1606ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 4.0% {1397ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 3.7% {1292ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 3.2% {1117ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ | 2.7% {943ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [[2.6% {908ms} Array(ArrayedCollection)>>mergeSortFrom:to:src:dst:by: [ 2.6% {908ms} Symbol(String)>><= | 21.1% {7367ms} Browser>>selectedClass [19.8% {6913ms} VirtualRootModule>>allDefinitionsFor:onlyExported:detect: [ 18.3% {6389ms} VirtualRootModule(Module)>>deepSubAndDeltaModules [ 14.8% {5167ms} Module>>deltaModules [ |10.1% {3526ms} Module>>neighborModules [ | |9.5% {3317ms} Array(Collection)>>select:thenCollect: [ | | 7.3% {2549ms} Array(SequenceableCollection)>>select: [ | | |3.5% {1222ms} Array(SequenceableCollection)>>at: [ | | | 2.6% {908ms} primitives [ | | 2.1% {733ms} Array(SequenceableCollection)>>collect: [ |4.5% {1571ms} Array(SequenceableCollection)>>select: [ 2.9% {1012ms} VirtualRootModule(Module)>>deepSubmodulesDo: [ 2.8% {978ms} Module>>deepSubmodulesDo: [ 2.8% {978ms} Module>>deepSubmodulesDo: [ 2.5% {873ms} Module>>deepSubmodulesDo: | 12.0% {4190ms} Browser(CodeHolder)>>contentsChanged [11.9% {4155ms} Browser(Object)>>contentsChanged [ 11.9% {4155ms} Browser(Object)>>changed: [ 11.9% {4155ms} PluggableTextMorph>>update: [ 10.8% {3771ms} PluggableTextMorph>>getText [ 10.8% {3771ms} Browser>>contents [ 10.6% {3701ms} Browser>>selectedClassOrMetaClass [ 10.6% {3701ms} Browser>>selectedClass [ 10.0% {3491ms} VirtualRootModule>>allDefinitionsFor:onlyExported:detect: [ 9.0% {3142ms} VirtualRootModule(Module)>>deepSubAndDeltaModules [ 7.1% {2479ms} Module>>deltaModules [ 5.1% {1781ms} Module>>neighborModules [ 4.8% {1676ms} Array(Collection)>>select:thenCollect: [ 3.3% {1152ms} Array(SequenceableCollection)>>select: | 10.8% {3771ms} Browser>>setClassOrganizer [10.8% {3771ms} Browser>>selectedClass [ 10.3% {3596ms} VirtualRootModule>>allDefinitionsFor:onlyExported:detect: [ 9.3% {3247ms} VirtualRootModule(Module)>>deepSubAndDeltaModules [ 7.1% {2479ms} VirtualRootModule(Module)>>deltaModules [ 4.8% {1676ms} VirtualRootModule(Module)>>neighborModules [ |4.4% {1536ms} Array(Collection)>>select:thenCollect: [ | 2.8% {978ms} Array(SequenceableCollection)>>select: [ 2.2% {768ms} Array(SequenceableCollection)>>select: 7.1% {2479ms} WorldState>>interCyclePause: 7.1% {2479ms} Delay>>wait **Leaves** 28.5% {9950ms} Array(SequenceableCollection)>>at: 8.6% {3003ms} SmallInteger(Magnitude)>>between:and: 7.1% {2479ms} Delay>>wait 5.8% {2025ms} Array(SequenceableCollection)>>select: 5.2% {1815ms} Symbol(String)>><= 3.0% {1047ms} Array(SequenceableCollection)>>collect: 2.9% {1012ms} Array(SequenceableCollection)>>copyFrom:to: 2.7% {943ms} Array(SequenceableCollection)>>do: 2.3% {803ms} Array(ArrayedCollection)>>sort 2.2% {768ms} WriteStream>>nextPut:
**Memory** old +127,264 bytes young +69,612 bytes used +196,876 bytes free -196,876 bytes
**GCs** full 0 totalling 0ms (0.0% uptime) incr 1569 totalling 2,080ms (6.0% uptime), avg 1.0ms tenures 2 (avg 785 GCs/tenure) root table 0 overflows
Thanks Lex! That did even out the speed a lot. As you say, it could still feel more responsive, but its a big help.
There is one minor visual discrepancy with the LargeLists patch. Before applying it, the selected item had red text with a grey background. After the patch, the selected item has a thin black rectangle around it. Probably its the way Celeste likes things to look (I notice that w/o LargeLists, Celeste first does the black rectangle(momentarily), then the red text). Other than that, everything looks good.
Eddie
----- Original Message ----- From: "Lex Spoon" lex@cc.gatech.edu To: squeak-dev@lists.squeakfoundation.org Sent: Sunday, September 08, 2002 11:19 AM Subject: Re: Speeding up the Browser
Ah, if it's the UI bogging down on large lists, then my LargeLists patch might fix this up.... It avoids calculating string sizes for all of the entries in the list. You just load the patch and get this benefit -- no tweaking of Browser is necessary. (LargeLists also has an alternative way to specify the strings; the model can supply individual elements instead of having to supply the entire list. This is a big saving in Celeste, where even *calculating* the lines is expensive.)
Okay, with LargeLists, it still seems It still seems a little sluggish to me, but it no longer matters how many items are in the list. Morph and HandMorphForReplay are selected equally fast.
-Lex
Brian Keefer wrote:
On a completely different matter, is Object>>hash safe? It seems to use the OOP address (as in a C pointer), which could change with each incremental GC.
Oh yeah, the hash bits remember it. As far as I can figure out, the first call to #hash sees the object header's hash bits set to 0, and makes one up then. Further calls to #hash see a nonzero value, and return the hash value.
Now, how do I clear my "stupid" bit?
squeak-dev@lists.squeakfoundation.org