Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
October 2009
- 86 participants
- 1118 messages
Re: [Pharo-project] [update] #10492 (1.0rc1)
by Niko Schwarz
Hi all, I made a follow-up patch like discussed on the workshop. Now
porting becomes as easy as changing "asNumber" to "squeezeOutNumber".
Name: SLICE-issue-1258-squeezeOutNumber-NikoSchwarz.2
This slice adds squeezeNumberOutOfString: to Number, as discussed in
the Pharo workshop. On the way, it
fixes an issue in SqNumberParser, where it would return itself rather
than the result of the failblack, when
parsing fails.
Also, a test is added to test and document the new squeezing number
out of strings behavior.
Example usage:
self assert: '123blabla' squeezeOutNumber equals: 123.
self assert: 'blabla123' squeezeOutNumber equals: 123.
self assert: 'blabla12blabla' squeezeOutNumber equals: 12.
self assert: ('12.3bla' squeezeOutNumber -12.3 ) abs < 0.0001.
self assert: '.1' squeezeOutNumber > 0.
Cheers,
Niko
On Tue, Oct 20, 2009 at 2:14 PM, Adrian Lienhard <adi(a)netstyle.ch> wrote:
> 10492 (this is the stream of the branch 1.0rc1)
> -----
>
> - Issue 1320: Â [squeak trunk] Sort the conflicts. This is required when
> merging a distant version, like Pharo for example...
> - Issue 1338: Â HostWindowTests>>testOne is failing in Windows
> - Issue 1345: Â Revert Number class>>readFrom: (was integrated with
> issue 1258)
>
> ___________________
> http://www.adrian-lienhard.ch/
>
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>
Oct. 24, 2009
[Pharo-project] PackageInfo>>overrideMethods
by Igor Stasenko
In both Pharo & Squeak has no senders:
overrideMethods
^ self extensionMethods select: [:ea | self isOvverideMethod: ea]
as well as #isOvverideMethod: not implemented, which makes this method
fail to work , even if it would be called by anyone.
--
Best regards,
Igor Stasenko AKA sig.
Oct. 24, 2009
[Pharo-project] About selectors returning an array
by Stéphane Ducasse
>
> Hi Eliot,
>>>> This is experimental, not guaranteed bugfree.
>>>> Indeed, you cannot #add: to nor #remove: from an Array... and
>>>> elements
>>>> won't be unique.
>>>> My trunk image did not freeze because I analyzed senders of
>>>> #selectors in
>>>> it.
>>>> But sure, this might break foreign code...
>>>> So yes, it deserves discussion.
>>>>
>>>> What do others think ?
>>>
>>> I agree with Eliot. Keep the changes minimal - so just replace
>>> "keys" with
>>> "keys asSet" where necessary.
>>>
>>> - Bert
>>
>> Me too. #selectors should return a Set.
>>
>> Colin
>>
>>
>
> Though I found no such usage in MC1.0 :)
> But I didn't inquire MC2.0, DeltaStreams, Etoys nor any other
> reflexion crunching packages...
>
> BTW, it would be great to have universal code analysis tools spreading
> over a public code database, not just my image. It dream of such
> database served through web pages...
>
> Nicolas
>
Last thing, before retracting this change, I give hereafter a little
rationale of my choice:
There were 92 senders of selectors in trunk, I classified into three
categories
1) Some senders performing add: or remove:
If I recall, only 3 of them were I placed some #asSet protection.
2) Some senders expecting unique keys :
but hey, selectors have unique elements because methodDictionary keys
are unique...
Only those aggregating with other selectors care, but most of them
explicitely addAll: to an empty IdentitySet...
3) Every others did use an Array compatible message like do: includes:
select: collect: asSortedCollection etc...
Then I analyzed the cost of selectors:
1) Array will perform better than Set for all these selectors, but
includes:.
2) Most direct senders of selector includes: SHOULD better be written
includesSelector:
Rationale: a single message send that will test includesKey: rather
than two creating unecessarily an intermediate Set
3) 95% of senders would now uselessly perform an additional #asSet
operation
So my analyze was that I would personnaly buy this little optimization
with the drawback of having to rewrite 5% of senders at most.
But of course, I don't offer to rewritte your code, so I understand
your opinion may differ :)
And of course I agree that optimized code that breaks has no value.
That's just a matter of tradeoffs.
Nicolas
Oct. 24, 2009
Re: [Pharo-project] Broken "Recover Lost Changes"
by Stéphane Ducasse
I think that the closure code shake a lot of foundation and that it
will take some cycles to get a stable system.
Now self is indeed not a message so was a period missing in your code?
Setf
On Oct 23, 2009, at 10:27 PM, John Toohey wrote:
> I have a 4 day old image that just froze. After restarting, I tried
> to recover the code changes since I saved my image yesterday, but
> the list of changes in the tool are an unordered list going back to
> February of this year. Even old code of mine from that time was in
> the list. After about an hour I managed to manually select the
> changes I've made since yesterday, and file them out. When I try to
> file them back in, I get an error from the debugger, and cannot
> continue. Anyone know what I can do to recover my source, or point
> me in the right direction to recover from this.
>
> This is the stacktrace from the debugger :-
>
> From: jt(a)parspro.com
> To: Pharo-project(a)lists.gforge.inria.fr
> Subject: [BUG]UndefinedObject(Object)>>doesNotUnderstand: #self
>
> here insert explanation of what you were doing, suspect changes
> you've made and so forth.
>
> 23 October 2009 4:19:05 pm
>
> VM: Mac OS - intel - 1058 - Squeak3.8.1 of '28 Aug 2006' [latest
> update: #6747] Squeak VM 4.1.1b2
> Image: Pharo1.0beta [Latest update: #10477]
>
> SecurityManager state:
> Restricted: false
> FileAccess: true
> SocketAccess: true
> Working Dir /Users/jpt/Dev/repos/Dev-Images/PharoCore-1.0-10477-BETA
> Trusted Dir /foobar/tooBar/forSqueak/bogus
> Untrusted Dir /Users/jpt/Library/Preferences/Squeak/Internet/My Squeak
>
> UndefinedObject(Object)>>doesNotUnderstand: #self
> Receiver: nil
> Arguments and temporary variables:
> aMessage: self
> exception: MessageNotUnderstood: receiver of "self" is nil
> resumeValue: nil
> Receiver's instance variables:
> nil
>
> UndefinedObject>>DoIt
> Receiver: nil
> Arguments and temporary variables:
>
> Receiver's instance variables:
> nil
>
> Compiler>>evaluate:in:to:notifying:ifFail:logged:
> Receiver: a Compiler
> Arguments and temporary variables:
> textOrStream: 'publish
> self status: #Opened
> '
> aContext: nil
> receiver: nil
> aRequestor: nil
> failBlock: [closure] in Compiler
> class>>evaluate:for:notifying:logged:
> logFlag: false
> methodNode: DoIt
> ^ publish self status: #Opened
> method: a CompiledMethod(982: UndefinedObject>>DoIt)
> value: nil
> toLog: nil
> itsSelection: nil
> itsSelectionString: nil
> Receiver's instance variables:
> sourceStream: a ReadStream 'publish
> self status: #Opened
> '
> requestor: nil
> class: UndefinedObject
> category: nil
> context: nil
> parser: a Parser
>
> Compiler class>>evaluate:for:notifying:logged:
> Receiver: Compiler
> Arguments and temporary variables:
> textOrString: 'publish
> self status: #Opened
> '
> anObject: nil
> aController: nil
> logFlag: false
> Receiver's instance variables:
> superclass: Object
> methodDict: a MethodDictionary
> (#compile:in:classified:notifying:ifFail:->a Comp...etc...
> format: 142
> instanceVariables: #('sourceStream' 'requestor' 'class'
> 'category' 'context' 'p...etc...
> organization: ('deprecated' format:in:notifying:contentsSymbol:)
> ('error handli...etc...
> subclasses: nil
> name: #Compiler
> classPool: a Dictionary()
> sharedPools: nil
> environment: Smalltalk
> category: #'Compiler-Kernel'
> traitComposition: nil
> localSelectors: nil
>
> Compiler class>>evaluate:for:logged:
> Receiver: Compiler
> Arguments and temporary variables:
> textOrString: 'publish
> self status: #Opened
> '
> anObject: nil
> logFlag: false
> Receiver's instance variables:
> superclass: Object
> methodDict: a MethodDictionary
> (#compile:in:classified:notifying:ifFail:->a Comp...etc...
> format: 142
> instanceVariables: #('sourceStream' 'requestor' 'class'
> 'category' 'context' 'p...etc...
> organization: ('deprecated' format:in:notifying:contentsSymbol:)
> ('error handli...etc...
> subclasses: nil
> name: #Compiler
> classPool: a Dictionary()
> sharedPools: nil
> environment: Smalltalk
> category: #'Compiler-Kernel'
> traitComposition: nil
> localSelectors: nil
>
> Compiler class>>evaluate:
> Receiver: Compiler
> Arguments and temporary variables:
> textOrString: 'publish
> self status: #Opened
> '
> Receiver's instance variables:
> superclass: Object
> methodDict: a MethodDictionary
> (#compile:in:classified:notifying:ifFail:->a Comp...etc...
> format: 142
> instanceVariables: #('sourceStream' 'requestor' 'class'
> 'category' 'context' 'p...etc...
> organization: ('deprecated' format:in:notifying:contentsSymbol:)
> ('error handli...etc...
> subclasses: nil
> name: #Compiler
> classPool: a Dictionary()
> sharedPools: nil
> environment: Smalltalk
> category: #'Compiler-Kernel'
> traitComposition: nil
> localSelectors: nil
>
> [] in ChangeRecord>>fileIn
> Receiver: a ChangeRecord
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> file: MultiByteFileStream: '/Users/jpt/Dev/repos/Dev-Images/
> PharoCore-1.0-10477...etc...
> position: 29712
> type: #doIt
> class: nil
> category: nil
> meta: nil
> stamp: nil
>
> BlockClosure>>ensure:
> Receiver: [closure] in ChangeRecord>>fileIn
> Arguments and temporary variables:
> aBlock: [closure] in CursorWithMask(Cursor)>>showWhile:
> returnValue: nil
> b: nil
> Receiver's instance variables:
> outerContext: ChangeRecord>>fileIn
> startpc: 107
> numArgs: 0
>
> CursorWithMask(Cursor)>>showWhile:
> Receiver: ((CursorWithMask
> extent: 16@16
> depth: 1
> fromArray: #(
> 2r0
> 2r0
> 2r0
> 2r10000000010...etc...
> Arguments and temporary variables:
> aBlock: [closure] in ChangeRecord>>fileIn
> oldcursor: ((CursorWithMask
> extent: 16@16
> depth: 1
> fromArray: #(
> 2r0
> 2r1...etc...
> Receiver's instance variables:
> bits: a Bitmap of length 16
> width: 16
> height: 16
> depth: 1
> offset: -1@-1
> maskForm: Form(16x16x1)
>
> ChangeRecord>>fileIn
> Receiver: a ChangeRecord
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> file: MultiByteFileStream: '/Users/jpt/Dev/repos/Dev-Images/
> PharoCore-1.0-10477...etc...
> position: 29712
> type: #doIt
> class: nil
> category: nil
> meta: nil
> stamp: nil
>
> [] in ChangeList>>fileInSelections
> Receiver: a ChangeList
> Arguments and temporary variables:
> any: true
> selected: a ChangeRecord
> item: #(true)
> Receiver's instance variables:
> dependents: a DependentsArray(a SystemWindow(252) a
> PluggableListMorphOfMany(33...etc...
> contents: ''
> currentCompiledMethod: nil
> contentsSymbol: #showDiffs
> changeList: an OrderedCollection(a ChangeRecord a ChangeRecord a
> ChangeRecord a...etc...
> list: an OrderedCollection('do it: ''From Pharo1.0beta of
> 16...ber 2009 at 3:57...etc...
> listIndex: 0
> listSelections: #(true true true true true true true true true
> true true true t...etc...
> file: MultiByteFileStream: '/Users/jpt/Dev/repos/Dev-Images/
> PharoCore-1.0-10477...etc...
> lostMethodPointer: nil
> showsVersions: nil
>
> Array(SequenceableCollection)>>with:do:
> Receiver: #(true true true true true true true true true true true
> true true true true true true tru...etc...
> Arguments and temporary variables:
> otherCollection: an OrderedCollection(a ChangeRecord a
> ChangeRecord a ChangeRec...etc...
> twoArgBlock: [closure] in ChangeList>>fileInSelections
> index: 171
> indexLimiT: 274
> Receiver's instance variables:
> #(true true true true true true true true true true true true true
> true true true true tru...etc...
>
> ChangeList>>fileInSelections
> Receiver: a ChangeList
> Arguments and temporary variables:
> any: #(true)
> Receiver's instance variables:
> dependents: a DependentsArray(a SystemWindow(252) a
> PluggableListMorphOfMany(33...etc...
> contents: ''
> currentCompiledMethod: nil
> contentsSymbol: #showDiffs
> changeList: an OrderedCollection(a ChangeRecord a ChangeRecord a
> ChangeRecord a...etc...
> list: an OrderedCollection('do it: ''From Pharo1.0beta of
> 16...ber 2009 at 3:57...etc...
> listIndex: 0
> listSelections: #(true true true true true true true true true
> true true true t...etc...
> file: MultiByteFileStream: '/Users/jpt/Dev/repos/Dev-Images/
> PharoCore-1.0-10477...etc...
> lostMethodPointer: nil
> showsVersions: nil
>
> PluggableButtonMorph>>performAction
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
>
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> [] in PluggableButtonMorph>>mouseUp:
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> Array(SequenceableCollection)>>do:
> Receiver: an Array(a PluggableButtonMorph(786) a
> PluggableButtonMorph(3485) a PluggableButtonMorph(5...etc...
> Arguments and temporary variables:
> aBlock: [closure] in PluggableButtonMorph>>mouseUp:
> index: 4
> indexLimiT: 4
> Receiver's instance variables:
> an Array(a PluggableButtonMorph(786) a PluggableButtonMorph(3485) a
> PluggableButtonMorph(5...etc...
>
> PluggableButtonMorph>>mouseUp:
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
> evt: [1518@375 mouseUp 3690378 nil]
> all: an Array(a PluggableButtonMorph(786) a PluggableButtonMorph
> (3485) a Plugga...etc...
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> PluggableButtonMorph(Morph)>>handleMouseUp:
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> MouseButtonEvent>>sentTo:
> Receiver: [1518@375 mouseUp 3690378 nil]
> Arguments and temporary variables:
> anObject: a PluggableButtonMorph(824)
> Receiver's instance variables:
> timeStamp: 3690378
> source: a HandMorph(3216)
> windowIndex: nil
> type: #mouseUp
> buttons: 0
> position: 1518@375
> handler: nil
> wasHandled: true
> whichButton: 4
>
> PluggableButtonMorph(Morph)>>handleEvent:
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> PluggableButtonMorph(Morph)>>handleFocusEvent:
> Receiver: a PluggableButtonMorph(824)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> Receiver's instance variables:
> bounds: 1408@359 corner: 1749@383
> owner: an AlignmentMorph(3699)
> submorphs: an Array(an AlignmentMorph(921))
> fullBounds: 1408@359 corner: 1749@383
> color: (Color r: 0.827 g: 0.827 b: 0.827)
> extension: a MorphExtension (1404) [balloonText] [other:
> (layoutPolicy -> a T...etc...
> borderWidth: 0
> borderColor: Color transparent
> model: a ChangeList
> label: 'file in selections'
> getStateSelector: nil
> actionSelector: #fileInSelections
> getLabelSelector: nil
> getMenuSelector: nil
> shortcutCharacter: nil
> askBeforeChanging: true
> triggerOnMouseDown: false
> offColor: Color white
> onColor: Color white
> feedbackColor: nil
> showSelectionFeedback: false
> allButtons: nil
> arguments: #()
> argumentsProvider: nil
> argumentsSelector: nil
>
> [] in HandMorph>>sendFocusEvent:to:clear:
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> [] in PasteUpMorph>>becomeActiveDuring:
> Receiver: a PasteUpMorph(1622) [world]
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> bounds: 0@0 corner: 1920@1178
> owner: nil
> submorphs: an Array(a TaskbarMorph(3095) a SystemWindow(3356) a
> SystemWindow(25...etc...
> fullBounds: nil
> color: Color gray
> extension: a MorphExtension (2543) [eventHandler = an
> EventHandler] [other: (...etc...
> borderWidth: 0
> borderColor: (Color r: 0.5 g: 0.5 b: 0.5)
> presenter: a Presenter (1246)
> model: a MorphicModel(1926)
> cursor: 1
> padding: 3
> backgroundMorph: nil
> isPartsBin: nil
> autoLineLayout: false
> indicateCursor: nil
> resizeToFit: nil
> wantsMouseOverHalos: nil
> worldState: a WorldState
> griddingOn: nil
>
> BlockClosure>>on:do:
> Receiver: [closure] in PasteUpMorph>>becomeActiveDuring:
> Arguments and temporary variables:
> exception: Error
> handlerAction: [closure] in PasteUpMorph>>becomeActiveDuring:
> handlerActive: false
> Receiver's instance variables:
> outerContext: PasteUpMorph>>becomeActiveDuring:
> startpc: 67
> numArgs: 0
>
> PasteUpMorph>>becomeActiveDuring:
> Receiver: a PasteUpMorph(1622) [world]
> Arguments and temporary variables:
> aBlock: [closure] in HandMorph>>sendFocusEvent:to:clear:
> priorWorld: a PasteUpMorph(1622) [world]
> priorHand: a HandMorph(3216)
> priorEvent: [1518@375 mouseOver red nil nil]
> Receiver's instance variables:
> bounds: 0@0 corner: 1920@1178
> owner: nil
> submorphs: an Array(a TaskbarMorph(3095) a SystemWindow(3356) a
> SystemWindow(25...etc...
> fullBounds: nil
> color: Color gray
> extension: a MorphExtension (2543) [eventHandler = an
> EventHandler] [other: (...etc...
> borderWidth: 0
> borderColor: (Color r: 0.5 g: 0.5 b: 0.5)
> presenter: a Presenter (1246)
> model: a MorphicModel(1926)
> cursor: 1
> padding: 3
> backgroundMorph: nil
> isPartsBin: nil
> autoLineLayout: false
> indicateCursor: nil
> resizeToFit: nil
> wantsMouseOverHalos: nil
> worldState: a WorldState
> griddingOn: nil
>
> HandMorph>>sendFocusEvent:to:clear:
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> focusHolder: a PluggableButtonMorph(824)
> aBlock: [closure] in HandMorph>>sendMouseEvent:
> w: a PasteUpMorph(1622) [world]
> result: #(nil)
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> HandMorph>>sendEvent:focus:clear:
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> focusHolder: a PluggableButtonMorph(824)
> aBlock: [closure] in HandMorph>>sendMouseEvent:
> result: nil
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> HandMorph>>sendMouseEvent:
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> HandMorph>>handleEvent:
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> anEvent: [1518@375 mouseUp 3690378 nil]
> evt: [1518@375 mouseUp 3690378 nil]
> ofs: nil
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> HandMorph>>processEvents
> Receiver: a HandMorph(3216)
> Arguments and temporary variables:
> evt: [1518@375 mouseUp 3690378 nil]
> evtBuf: #(1 3690378 1518 375 0 0 0 1)
> type: 1
> hadAny: false
> Receiver's instance variables:
> bounds: 1661@782 corner: 1677@798
> owner: a PasteUpMorph(1622) [world]
> submorphs: #()
> fullBounds: 1661@782 corner: 1677@798
> color: Color blue
> extension: a MorphExtension (539) [eventHandler = an EventHandler]
> mouseFocus: nil
> keyboardFocus: nil
> eventListeners: nil
> mouseListeners: nil
> keyboardListeners: nil
> mouseClickState: nil
> mouseOverHandler: a MouseOverHandler
> lastMouseEvent: [1661@782 mouseUp 3788444 nil]
> targetOffset: 99@6
> damageRecorder: a DamageRecorder
> cacheCanvas: nil
> cachedCanvasHasHoles: true
> temporaryCursor: nil
> temporaryCursorOffset: nil
> hardwareCursor: nil
> hasChanged: true
> savedPatch: nil
> userInitials: ''
> lastEventBuffer: #(1 3788444 1661 782 0 0 0 1)
> lastKeyScanCode: 126
> combinedChar: nil
>
> [] in WorldState>>doOneCycleNowFor:
> Receiver: a WorldState
> Arguments and temporary variables:
> <<error during printing>
> Receiver's instance variables:
> hands: an Array(a HandMorph(3216))
> viewBox: 0@0 corner: 1920@1178
> canvas: a FormCanvas on: DisplayScreen(1920x1178x32)
> damageRecorder: a DamageRecorder
> stepList: a Heap(StepMessage(#stepAt: -> 3PButton
> (#togglePrettyDiffing 247))(3P...etc...
> lastStepTime: 3788426
> lastStepMessage: nil
> lastCycleTime: 3788446
> commandHistory: a CommandHistory
> alarms: a Heap()
> lastAlarmTime: 3788426
>
> Array(SequenceableCollection)>>do:
> Receiver: an Array(a HandMorph(3216))
> Arguments and temporary variables:
> aBlock: [closure] in WorldState>>doOneCycleNowFor:
> index: 1
> indexLimiT: 1
> Receiver's instance variables:
> an Array(a HandMorph(3216))
>
> WorldState>>handsDo:
> Receiver: a WorldState
> Arguments and temporary variables:
> aBlock: [closure] in WorldState>>doOneCycleNowFor:
> Receiver's instance variables:
> hands: an Array(a HandMorph(3216))
> viewBox: 0@0 corner: 1920@1178
> canvas: a FormCanvas on: DisplayScreen(1920x1178x32)
> damageRecorder: a DamageRecorder
> stepList: a Heap(StepMessage(#stepAt: -> 3PButton
> (#togglePrettyDiffing 247))(3P...etc...
> lastStepTime: 3788426
> lastStepMessage: nil
> lastCycleTime: 3788446
> commandHistory: a CommandHistory
> alarms: a Heap()
> lastAlarmTime: 3788426
>
> WorldState>>doOneCycleNowFor:
> Receiver: a WorldState
> Arguments and temporary variables:
> aWorld: a PasteUpMorph(1622) [world]
> Receiver's instance variables:
> hands: an Array(a HandMorph(3216))
> viewBox: 0@0 corner: 1920@1178
> canvas: a FormCanvas on: DisplayScreen(1920x1178x32)
> damageRecorder: a DamageRecorder
> stepList: a Heap(StepMessage(#stepAt: -> 3PButton
> (#togglePrettyDiffing 247))(3P...etc...
> lastStepTime: 3788426
> lastStepMessage: nil
> lastCycleTime: 3788446
> commandHistory: a CommandHistory
> alarms: a Heap()
> lastAlarmTime: 3788426
>
> WorldState>>doOneCycleFor:
> Receiver: a WorldState
> Arguments and temporary variables:
> aWorld: a PasteUpMorph(1622) [world]
> Receiver's instance variables:
> hands: an Array(a HandMorph(3216))
> viewBox: 0@0 corner: 1920@1178
> canvas: a FormCanvas on: DisplayScreen(1920x1178x32)
> damageRecorder: a DamageRecorder
> stepList: a Heap(StepMessage(#stepAt: -> 3PButton
> (#togglePrettyDiffing 247))(3P...etc...
> lastStepTime: 3788426
> lastStepMessage: nil
> lastCycleTime: 3788446
> commandHistory: a CommandHistory
> alarms: a Heap()
> lastAlarmTime: 3788426
>
> PasteUpMorph>>doOneCycle
> Receiver: a PasteUpMorph(1622) [world]
> Arguments and temporary variables:
>
> Receiver's instance variables:
> bounds: 0@0 corner: 1920@1178
> owner: nil
> submorphs: an Array(a TaskbarMorph(3095) a SystemWindow(3356) a
> SystemWindow(25...etc...
> fullBounds: nil
> color: Color gray
> extension: a MorphExtension (2543) [eventHandler = an
> EventHandler] [other: (...etc...
> borderWidth: 0
> borderColor: (Color r: 0.5 g: 0.5 b: 0.5)
> presenter: a Presenter (1246)
> model: a MorphicModel(1926)
> cursor: 1
> padding: 3
> backgroundMorph: nil
> isPartsBin: nil
> autoLineLayout: false
> indicateCursor: nil
> resizeToFit: nil
> wantsMouseOverHalos: nil
> worldState: a WorldState
> griddingOn: nil
>
> [] in Project class>>spawnNewProcess
> Receiver: Project
> Arguments and temporary variables:
>
> Receiver's instance variables:
> superclass: Model
> methodDict: a MethodDictionary(size 167)
> format: 172
> instanceVariables: #('world' 'changeSet' 'transcript'
> 'parentProject' 'previous...etc...
> organization: ('*Polymorph-Widgets'
> assureTaskbarPresenceMatchesPreference crea...etc...
> subclasses: nil
> name: #Project
> classPool: a Dictionary(#AllProjects->an OrderedCollection(a
> Project(Juliet)) #...etc...
> sharedPools: nil
> environment: Smalltalk
> category: #'System-Support'
> traitComposition: {}
> localSelectors: nil
>
> [] in BlockClosure>>newProcess
> Receiver: [closure] in Project class>>spawnNewProcess
> Arguments and temporary variables:
>
> Receiver's instance variables:
> outerContext: Project class>>spawnNewProcess
> startpc: 53
> numArgs: 0
>
>
> --- The full stack ---
> UndefinedObject(Object)>>doesNotUnderstand: #self
> UndefinedObject>>DoIt
> Compiler>>evaluate:in:to:notifying:ifFail:logged:
> Compiler class>>evaluate:for:notifying:logged:
> Compiler class>>evaluate:for:logged:
> Compiler class>>evaluate:
> [] in ChangeRecord>>fileIn
> BlockClosure>>ensure:
> CursorWithMask(Cursor)>>showWhile:
> ChangeRecord>>fileIn
> [] in ChangeList>>fileInSelections
> Array(SequenceableCollection)>>with:do:
> ChangeList>>fileInSelections
> PluggableButtonMorph>>performAction
> [] in PluggableButtonMorph>>mouseUp:
> Array(SequenceableCollection)>>do:
> PluggableButtonMorph>>mouseUp:
> PluggableButtonMorph(Morph)>>handleMouseUp:
> MouseButtonEvent>>sentTo:
> PluggableButtonMorph(Morph)>>handleEvent:
> PluggableButtonMorph(Morph)>>handleFocusEvent:
> [] in HandMorph>>sendFocusEvent:to:clear:
> [] in PasteUpMorph>>becomeActiveDuring:
> BlockClosure>>on:do:
> PasteUpMorph>>becomeActiveDuring:
> HandMorph>>sendFocusEvent:to:clear:
> HandMorph>>sendEvent:focus:clear:
> HandMorph>>sendMouseEvent:
> HandMorph>>handleEvent:
> HandMorph>>processEvents
> [] in WorldState>>doOneCycleNowFor:
> Array(SequenceableCollection)>>do:
> WorldState>>handsDo:
> WorldState>>doOneCycleNowFor:
> WorldState>>doOneCycleFor:
> PasteUpMorph>>doOneCycle
> [] in Project class>>spawnNewProcess
> [] in BlockClosure>>newProcess
>
>
> --
> -JT
>
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Oct. 24, 2009
Re: [Pharo-project] Hashed collection changes, the performance graphs
by Martin McClure
Martin McClure wrote:
> Gotta go see my wife in a play now; will comment on these graphs later.
The play was fun :-)
Now about the graphs:
The test code, a variant of the test from the HashTable SqueakSource
wiki, is at the bottom of this message. Basically, it adds a bunch of
instances of Object to a Dictionary and sees how much time it takes to
look them up again.
From the graphs in the previous message, you can see that performance
for sizes > 4000 is greatly improved. For size = 10000, #at: is 1000
times faster, 2-3 microseconds vs. >2 milliseconds. At size=10000,
#at:put: is about 200 times faster, ~10 microseconds vs. >2
milliseconds, and the large spikes for growing the collection are 21
milliseconds vs. > 4 seconds, again a factor of about 200.
Performance for dictionary sizes < 4000 is essentially the same as
before, so these collections can serve as general-purpose collections
over a wide range of sizes. I've attached the graphs for sizes <4000 to
this message so you can see that more clearly than on the previous graphs.
These results should hold for any object that inherits #hash from
Object, in other words uses its identity hash as its equality hash.
Other objects with better hashes did not have as serious a problem, but
will probably show increased performance as well due to using prime
table sizes.
These changes are in Set, so should improve Set's subclasses as well.
IdentityDictionary, IdentitySet, and WeakIdentityKeyDictionary did not
have as serious a problem, but should see some improvement.
MethodDictionaries have been left alone on the assumption that the VM
depends on the hashing of those.
Since there are still only 4K possible values of identity hash,
collisions are inevitable in large collections, and the number of
collisions will grow linearly with collection size. So how well does the
spread hash / prime table size do at even larger sizes? I ran the same
test at sizes of one million. As expected, access was quite a bit slower
than it had been at 10000. Time for #at: was ~250 microseconds, and
#at:put: was about the same. Note, however, that this is still ten times
faster than Dictionary previously was at a size of 10000; 100 times
larger yet 10 times faster.
I had a lot of fun doing this. This is better results than I expected,
for a fairly minor (though deep) code change.
Regards,
-Martin
| test ord |
Transcript cr.
test := Dictionary new.
[ test size >= 10000] whileFalse: [
ord := OrderedCollection new: 100.
Transcript show:
[
100 timesRepeat: [
test at: ( ord add: Object new ) put: nil ].
] timeToRun asString.
Transcript tab;
show: test size asString;
tab.
Transcript show:
[
1000 timesRepeat: [
ord do: [ :each | test at: each ] ]
] timeToRun asString.
Transcript tab; show:
[
1000 timesRepeat: [
ord do: [ :each | ] ]
] timeToRun asString.
Transcript cr ]
Oct. 24, 2009
[Pharo-project] question about results of MessageTally
by Laval Jannik
Hi,
when I use MassageTally>>spyOn: on the creation of a Dictionary,
results have not the same details according to the size of Dictionary.
For example:
===
|n|
MessageTally spyOn:[
n := Dictionary new.
1 to: 400000 do:[:each | n at: each put:each].
]
===
returns this results:
====
- 1745 tallies, 1751 msec.
**Tree**
--------------------------------
Process: (40s) 1964: nil
--------------------------------
45.8% {802ms} Dictionary(Set)>>atNewIndex:put:
|43.6% {763ms} Dictionary(Set)>>fullCheck
| |39.4% {690ms} Dictionary(Set)>>grow
| | |27.2% {476ms} Dictionary>>noCheckAdd:
| | | |25.2% {441ms} Dictionary(Set)>>findElementOrNil:
| | | | |23.6% {413ms} Dictionary>>scanFor:
| | | | |1.6% {28ms} primitives
| | | |2.0% {35ms} primitives
| | |9.2% {161ms} primitives
| | |3.0% {53ms} Array(SequenceableCollection)>>do:
| |2.4% {42ms} primitives
| |1.8% {32ms} SmallInteger(Magnitude)>>max:
|2.2% {39ms} primitives
22.4% {392ms} Association class>>key:value:
|18.9% {331ms} Association class(LookupKey class)>>key:
| |16.3% {285ms} Association(LookupKey)>>key:
| |2.6% {46ms} primitives
|1.9% {33ms} Association>>value:
|1.6% {28ms} primitives
4.4% {77ms} Dictionary(Set)>>findElementOrNil:
|2.3% {40ms} primitives
|2.1% {37ms} Dictionary>>scanFor:
1.9% {33ms} primitives
====
But, if I do:
===
|n|
MessageTally spyOn:[
n := Dictionary new.
1 to: 4000000 do:[:each | n at: each put:each].
]
===
results are:
====
- 179772 tallies, 180312 msec.
**Tree**
--------------------------------
Process: (40s) 1964: nil
--------------------------------
3.1% {5590ms} Dictionary(Set)>>atNewIndex:put:
|2.8% {5049ms} Dictionary(Set)>>fullCheck
| 2.3% {4147ms} Dictionary(Set)>>grow
| 1.3% {2344ms} Dictionary>>noCheckAdd:
1.0% {1803ms} Association class>>key:value:
====
Where are the rest of the process ?
Does anybody understand this behavior ? can you explain ?
Cheers,
Jannik
Oct. 24, 2009
[Pharo-project] Hashed collection changes, the performance graphs
by Martin McClure
Gotta go see my wife in a play now; will comment on these graphs later.
-Martin
Oct. 24, 2009
[Pharo-project] Hashed collection improvements: Some code
by Martin McClure
OK, here's a filein that improves Pharo hashed collection performance
quite a bit. Large collections are much faster, and small ones are
pretty much the same speed as before. There are basically two fairly
simple changes; the basic structure and algorithms of the collections is
unchanged. The changes:
1. Spread identity hash values.
2. Make table sizes prime.
File it into PharoCore-1.0-10491rc1.image. It'll take a minute or two
since it has to rehash the world halfway through. I don't know how to
make another kind of packaging that can do that, so I'll leave that to
someone else.
After the filein, there are some test failures, most of which do not
seem to be *directly* related. I'm hoping someone that knows the
affected tests can take a look and comment:
Unexpectedly pass ObjectFinalizerTests>>#testFinalizationOfEquals
Not clear why, but this does not seem to be a problem :-)
Fails HostWindowTests>>#testOne
But this test fails in the core image on Linux; HostWindows do not
seem to be implemented for Linux.
Error on FontTest>>#testMultistringFont
Japanese StrikeFonts have nil characterToGlyphMap,
#createCharacterToGlyphMap answers nil,
not immediately clear how this is supposed to be initialized for fonts
with codepoints > 255.
PackageInfoTest>>testKernelPackage
because some method in kernel package for Object is not in Object.
I've changed #hash, so that's probably it.
Regards,
-Martin
'From Pharo1.0rc1 of 19 October 2009 [Latest update: #10491] on 23 October 2009 at 5:54:55 pm'!
!ProtoObject methodsFor: 'comparing' stamp: 'MartinMcClure 10/22/2009 22:30'!
identityHashTEMP
"Answer a SmallInteger whose value is related to the receiver's identity.
This method must not be overridden, except by SmallInteger.
Primitive. Fails if the receiver is a SmallInteger. Essential.
See Object documentation whatIsAPrimitive.
Do not override."
^self primIdentityHash bitShift: 18! !
!Object methodsFor: 'comparing' stamp: 'MartinMcClure 10/22/2009 22:46'!
hashTEMP
"Answer a SmallInteger whose value is related to the receiver's identity.
May be overridden, and should be overridden in any classes that define = "
^ self primIdentityHash bitShift: 18! !
!ProtoObject methodsFor: 'comparing' stamp: 'MartinMcClure 10/22/2009 21:13'!
primIdentityHash
"Answer a SmallInteger whose value is related to the receiver's identity.
This method must not be overridden, except by SmallInteger.
Primitive. Fails if the receiver is a SmallInteger. Essential.
See Object documentation whatIsAPrimitive.
Do not override."
<primitive: 75>
self primitiveFailed! !
!SmallInteger methodsFor: 'comparing' stamp: 'MartinMcClure 10/23/2009 17:53'!
primIdentityHash
"Senders of primIdentityHash do it because they expect to get an answer from 1-4095.
So they should not send this to SmallIntegers, but should use #identityHash"
"^self shouldNotImplement"
"...OK, only here for the sake of FixedIdentitySet, which may not need it since it is probably not used for Integers.
And FixedIdentitySet itself may not be needed now that IdentitySets are faster."
^self! !
!IdentityDictionary methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 14:55'!
scanFor: anObject
"Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or zero if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements."
| finish hash start element |
finish := array size.
start := (anObject identityHash \\ finish) + 1.
"Search from (hash mod size) to the end."
start to: finish do:
[:index | ((element := array at: index) == nil or: [element key == anObject])
ifTrue: [^ index ]].
"Search from 1 to where we started."
1 to: start-1 do:
[:index | ((element := array at: index) == nil or: [element key == anObject])
ifTrue: [^ index ]].
^ 0 "No match AND no empty slot"! !
!IdentitySet methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 14:57'!
scanFor: anObject
"Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or zero if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements."
| finish hash start element |
finish := array size.
start := (anObject identityHash \\ finish) + 1.
"Search from (hash mod size) to the end."
start to: finish do:
[:index | ((element := array at: index) == nil or: [element == anObject])
ifTrue: [^ index ]].
"Search from 1 to where we started."
1 to: start-1 do:
[:index | ((element := array at: index) == nil or: [element == anObject])
ifTrue: [^ index ]].
^ 0 "No match AND no empty slot"! !
!MethodDictionary methodsFor: 'private' stamp: 'MartinMcClure 10/22/2009 21:24'!
scanFor: anObject
"Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or zero if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements."
| element start finish |
finish := array size.
start := (anObject primIdentityHash \\ finish) + 1.
"Search from (hash mod size) to the end."
start to: finish do:
[:index | ((element := self basicAt: index) == nil or: [element == anObject])
ifTrue: [^ index ]].
"Search from 1 to where we started."
1 to: start-1 do:
[:index | ((element := self basicAt: index) == nil or: [element == anObject])
ifTrue: [^ index ]].
^ 0 "No match AND no empty slot"! !
!WeakIdentityKeyDictionary methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 14:54'!
scanFor: anObject
"ar 10/21/2000: The method has been copied to this location to indicate that whenever #scanFor: changes #scanForNil: must be changed in the receiver as well."
"Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or zero if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements."
| element start finish hash |
finish := array size.
start := (anObject identityHash \\ finish) + 1.
"Search from (hash mod size) to the end."
start to: finish do:
[:index | ((element := array at: index) == nil or: [element key == anObject])
ifTrue: [^ index ]].
"Search from 1 to where we started."
1 to: start-1 do:
[:index | ((element := array at: index) == nil or: [element key == anObject])
ifTrue: [^ index ]].
^ 0 "No match AND no empty slot"! !
!WeakIdentityKeyDictionary methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 14:54'!
scanForNil: anObject
"Private. Scan the key array for the first slot containing nil (indicating an empty slot). Answer the index of that slot."
| start finish hash |
finish := array size.
start := (anObject identityHash \\ array size) + 1.
"Search from (hash mod size) to the end."
start to: finish do:
[:index | (array at: index) == nil ifTrue: [^ index ]].
"Search from 1 to where we started."
1 to: start-1 do:
[:index | (array at: index) == nil ifTrue: [^ index ]].
^ 0 "No match AND no empty slot"! !
"---------------------Do surgery and rehash before continuing--------------------------"!
| dict method |
dict := ProtoObject methodDictionary.
method := dict at: #identityHashTEMP.
dict at: #identityHash put: method.
dict := Object methodDictionary.
method := dict at: #hashTEMP.
dict at: #identityHash put: method.
Set rehashAllSets.!
"---------- Life should be... better now :-) -----------------------------"!
!ProtoObject methodsFor: 'comparing' stamp: 'MartinMcClure 10/22/2009 22:30'!
identityHash
"Answer a SmallInteger whose value is related to the receiver's identity.
This method must not be overridden, except by SmallInteger.
Primitive. Fails if the receiver is a SmallInteger. Essential.
See Object documentation whatIsAPrimitive.
Do not override."
^self primIdentityHash bitShift: 18! !
!Object methodsFor: 'comparing' stamp: 'MartinMcClure 10/22/2009 22:46'!
hash
"Answer a SmallInteger whose value is related to the receiver's identity.
May be overridden, and should be overridden in any classes that define = "
^ self primIdentityHash bitShift: 18! !
!FixedIdentitySet methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 14:49'!
indexOf: anObject
anObject isNil ifTrue: [self error: 'This class collection cannot handle nil as an element'].
^ (anObject primIdentityHash bitAnd: self basicSize - 1) + 1! !
!Set class methodsFor: 'sizing' stamp: 'MartinMcClure 10/23/2009 09:44'!
goodPrimes
"Answer a sorted array of prime numbers less than one hundred million
that make good hash table sizes. Should be expanded to more numbers if folks
want to make larger collections.
Need to check with Andres' book when I get back to work to see if I remembered
it right :-)
Generated with this code:
| prevPrime primes goodPrimes |
goodPrimes := OrderedCollection new.
primes := Integer largePrimesUpTo: 100000000.
goodPrimes add: 5.
prevPrime := 5.
primes do:
[:prime | prime > (prevPrime * 4 // 3) ifTrue:
[| lowByte | lowByte := prime bitAnd: 16rFF.
(lowByte > 10 and: [lowByte < 245]) ifTrue:
[goodPrimes add: prime.
prevPrime := prime]]].
^goodPrimes asArray printString"
^#(5 11 17 23 31 43 59 79 107 149 199 269 359 479 641 857 1151 1549 2069 2767 3691 4931 6577 8779 11717 15629 20849 27799 37087 49451 65951 87943 117259 156347 208463 277961 370619 494167 658897 878539 1171393 1561883 2082527 2776727 3702313 4936423 6581909 8775947 11701267 15601723 20802317 27736427 36981911 49309219 65745677 87660917)!
]style[(10 311 405 337)f2b,f2,f1,f2! !
!Set class methodsFor: 'sizing' stamp: 'MartinMcClure 10/23/2009 10:14'!
goodPrimeAtLeast: lowerLimit
"Answer the next good prime >= lowerlimit.
If lowerLimit is larger than the largest known good prime,
just make it odd."
| primes low mid high prime |
primes := self goodPrimes.
low := 1.
high := primes size.
lowerLimit > (primes at: high) ifTrue:
[^lowerLimit even
ifTrue: [lowerLimit + 1]
ifFalse: [lowerLimit]].
[mid := high - low // 2 + low.
prime := primes at: mid.
prime < lowerLimit
ifTrue: [low := mid]
ifFalse: [high := mid].
high - low <= 1 ifTrue:
[^primes at: high].
prime == lowerLimit ifTrue:
[^prime]] repeat
!
]style[(28 158 411)f2b,f2,f1! !
!Set methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 10:25'!
growSize
"Answer what my next higher table size should be"
^ self class goodPrimeAtLeast: array size * 2! !
!Set methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 10:25'!
grow
"Grow the elements array and reinsert the old elements"
| oldElements |
oldElements := array.
array := Array new: self growSize.
tally := 0.
oldElements do:
[:each | each == nil ifFalse: [self noCheckAdd: each]]! !
!Set class methodsFor: 'instance creation' stamp: 'MartinMcClure 10/23/2009 10:19'!
sizeFor: nElements
"Large enough size to hold nElements with some slop (see fullCheck)"
nElements <= 0 ifTrue: [^ 5].
^ self goodPrimeAtLeast: (nElements+1*4//3)! !
!WeakSet methodsFor: 'private' stamp: 'MartinMcClure 10/23/2009 10:26'!
grow
"Grow the elements array if needed.
Since WeakSets just nil their slots, alot of the occupied (in the eyes of the set) slots are usually empty. Doubling size if unneeded can lead to BAD performance, therefore we see if reassigning the <live> elements to a Set of similiar size leads to a sufficiently (50% used here) empty set first.
and reinsert the old elements"
|oldTally|
oldTally := tally.
self growTo: array size.
oldTally >> 1 < tally ifTrue: [
self growTo: self growSize]! !
!MethodPragmaTest methodsFor: 'testing-primitives' stamp: 'MartinMcClure 10/23/2009 12:37'!
testPrimitiveIndexed2
"This test useses the #identityHash primitive."
self compile: '<primitive: 75> ^ #idHash' selector: #idHash.
self assert: self idHash = self primIdentityHash.! !
!SmallInteger reorganize!
('arithmetic' * + - / // \\ gcd: quo:)
('bit manipulation' bitAnd: bitOr: bitShift: bitXor: hashMultiply highBit highBitOfMagnitude lowBit)
('comparing' < <= = > >= hash identityHash primIdentityHash ~=)
('converting' as31BitSmallInt asFloat)
('copying' clone deepCopy shallowCopy veryDeepCopyWith:)
('printing' decimalDigitLength destinationBuffer: numberOfDigitsInBase: printOn:base: printOn:base:nDigits: printString printStringBase: printStringBase:nDigits: threeDigitName)
('system primitives' asOop digitAt: digitAt:put: digitLength instVarAt: nextInstance nextObject)
('testing' even isLarge odd)
('private' fromString:radix: highBitOfPositiveReceiver)
!
!Set class reorganize!
('initialization' quickRehashAllSets rehashAllSets)
('sizing' goodPrimeAtLeast: goodPrimes)
('instance creation' new new: newFrom: sizeFor:)
!
ProtoObject removeSelector: #identityHashTEMP!
Object removeSelector: #hashTEMP!
!ProtoObject reorganize!
('apply primitives' tryNamedPrimitive tryNamedPrimitive: tryNamedPrimitive:with: tryNamedPrimitive:with:with: tryNamedPrimitive:with:with:with: tryNamedPrimitive:with:with:with:with: tryNamedPrimitive:with:with:with:with:with: tryNamedPrimitive:with:with:with:with:with:with: tryNamedPrimitive:with:with:with:with:with:with:with: tryPrimitive:withArgs:)
('closure-prims' privGetInstVar: privRemoteReturnTo: privSetInHolder: privSetInstVar:put: privStoreIn:instVar:)
('comparing' == identityHash primIdentityHash ~~)
('debugging' doOnlyOnce: flag: rearmOneShot withArgs:executeMethod:)
('initialize-release' initialize)
('method execution' executeMethod: with:executeMethod: with:with:executeMethod: with:with:with:executeMethod: with:with:with:with:executeMethod:)
('objects from disk' rehash)
('system primitives' become: cannotInterpret: doesNotUnderstand: nextInstance nextObject)
('testing' ifNil: ifNil:ifNotNil: ifNotNil: ifNotNil:ifNil: isInMemory isNil pointsTo:)
!
Oct. 24, 2009
Re: [Pharo-project] Thread-safe collections
by John M McIntosh
Not sure what you are looking for a couple of years back I chased down
a bug or two in the finalization logic
See WeakArray>>FinalizationSemaphore
and
WeakRegistry
accessLock := Semaphore forMutualExclusion.
Both attempt to ensure finalization occurs in thread safe manners,
this doesn't mean someone introduced something bad in the last 5 years
or so.
An example?
On 2009-10-23, at 5:44 PM, Schwab,Wilhelm K wrote:
> Stef,
>
> Dolphin's weak collections are typically (I suspect allways) thread
> safe, which I have attributed to the constant struggle with
> finalization - it seems natural (to me at least) for them to be
> protected. Some quick browsing leads me to think that this is not
> true in Pharo. Am I missing something, or do we also need some
> thread-safe weaklings?
>
> Bill
>
>
>
> -----Original Message-----
> From: pharo-project-bounces(a)lists.gforge.inria.fr [mailto:pharo-
> project-bounces(a)lists.gforge.inria.fr] On Behalf Of Stéphane Ducasse
> Sent: Friday, October 23, 2009 2:46 AM
> To: Pharo-project(a)lists.gforge.inria.fr
> Subject: Re: [Pharo-project] Thread-safe collections
>
> I would really like to see some packages getting implementing around
> the idea of a couple of robust and well tested thread safe
> collections.
>
> Stef
>
> On Oct 23, 2009, at 2:16 AM, Schwab,Wilhelm K wrote:
>
>> Sig,
>>
>> One can always construct examples in which protecting the entire
>> loop is the better option. That's not the scenario of interest.
>> Just as shared queues are useful, shared sets and dictionaries have
>> value for sporadic access scenarios. Doing it your way, everyone
>> writes their own incompletely protected (read buggy/dangerous) ad-
>> hoc
>> implementations of these common collections.
>>
>> I favor having solid implementations that are complete and as correct
>> as we can get them, leaving people to optimize as you suggest when it
>> makes sense to do so.
>>
>> Bill
>>
>>
>> -----Original Message-----
>> From: pharo-project-bounces(a)lists.gforge.inria.fr [mailto:pharo-
>> project-bounces(a)lists.gforge.inria.fr] On Behalf Of Igor Stasenko
>> Sent: Thursday, October 22, 2009 5:23 PM
>> To: Pharo-project(a)lists.gforge.inria.fr
>> Subject: Re: [Pharo-project] Thread-safe collections
>>
>> 2009/10/23 Schwab,Wilhelm K <bschwab(a)anest.ufl.edu>:
>>> Hello all,
>>>
>>> I just looked around for thread-safe collections, and found nothing
>>> that looks like a shared dictionary. The squeak-dev archives
>>> contain
>>> the obligatory newbie posts (wanting all collections to be thread
>>> safe) and the expected replies, some of which are overly dismissive
>>> of the idea. Something that protects things like
>>> #at:ifAbsentPut: and friends is _really_ useful. Am I missing an
>>> existing implementation?
>>>
>>
>> Imo, there's only one shared collection which is useful - shared
>> queue. :) If you need more kinds of thread-safe collections, it
>> probably indicating that the concurrent code (or model) which you
>> designed is in pretty bad shape.
>>
>> Just compare two following snippets:
>>
>> 1 to: 100 do: [:i | collection threadSafeAt: i put: something].
>>
>> and:
>>
>> semaphore critical: [ 1 to: 100 do: [:i | collection at: i put:
>> something] ].
>>
>> What you think, which one is better?
>>
>>
>>> Bill
>>>
>>>
>>> _______________________________________________
>>> Pharo-project mailing list
>>> Pharo-project(a)lists.gforge.inria.fr
>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>>
>>
>>
>>
>> --
>> Best regards,
>> Igor Stasenko AKA sig.
>>
>> _______________________________________________
>> Pharo-project mailing list
>> Pharo-project(a)lists.gforge.inria.fr
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>> _______________________________________________
>> Pharo-project mailing list
>> Pharo-project(a)lists.gforge.inria.fr
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
--
=
=
=
========================================================================
John M. McIntosh <johnmci(a)smalltalkconsulting.com> Twitter:
squeaker68882
Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com
=
=
=
========================================================================
Oct. 24, 2009
Re: [Pharo-project] Thread-safe collections
by Schwab,Wilhelm K
Stef,
Dolphin's weak collections are typically (I suspect allways) thread safe, which I have attributed to the constant struggle with finalization - it seems natural (to me at least) for them to be protected. Some quick browsing leads me to think that this is not true in Pharo. Am I missing something, or do we also need some thread-safe weaklings?
Bill
-----Original Message-----
From: pharo-project-bounces(a)lists.gforge.inria.fr [mailto:pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stéphane Ducasse
Sent: Friday, October 23, 2009 2:46 AM
To: Pharo-project(a)lists.gforge.inria.fr
Subject: Re: [Pharo-project] Thread-safe collections
I would really like to see some packages getting implementing around the idea of a couple of robust and well tested thread safe collections.
Stef
On Oct 23, 2009, at 2:16 AM, Schwab,Wilhelm K wrote:
> Sig,
>
> One can always construct examples in which protecting the entire
> loop is the better option. That's not the scenario of interest.
> Just as shared queues are useful, shared sets and dictionaries have
> value for sporadic access scenarios. Doing it your way, everyone
> writes their own incompletely protected (read buggy/dangerous) ad- hoc
> implementations of these common collections.
>
> I favor having solid implementations that are complete and as correct
> as we can get them, leaving people to optimize as you suggest when it
> makes sense to do so.
>
> Bill
>
>
> -----Original Message-----
> From: pharo-project-bounces(a)lists.gforge.inria.fr [mailto:pharo-
> project-bounces(a)lists.gforge.inria.fr] On Behalf Of Igor Stasenko
> Sent: Thursday, October 22, 2009 5:23 PM
> To: Pharo-project(a)lists.gforge.inria.fr
> Subject: Re: [Pharo-project] Thread-safe collections
>
> 2009/10/23 Schwab,Wilhelm K <bschwab(a)anest.ufl.edu>:
>> Hello all,
>>
>> I just looked around for thread-safe collections, and found nothing
>> that looks like a shared dictionary. The squeak-dev archives contain
>> the obligatory newbie posts (wanting all collections to be thread
>> safe) and the expected replies, some of which are overly dismissive
>> of the idea. Something that protects things like
>> #at:ifAbsentPut: and friends is _really_ useful. Am I missing an
>> existing implementation?
>>
>
> Imo, there's only one shared collection which is useful - shared
> queue. :) If you need more kinds of thread-safe collections, it
> probably indicating that the concurrent code (or model) which you
> designed is in pretty bad shape.
>
> Just compare two following snippets:
>
> 1 to: 100 do: [:i | collection threadSafeAt: i put: something].
>
> and:
>
> semaphore critical: [ 1 to: 100 do: [:i | collection at: i put:
> something] ].
>
> What you think, which one is better?
>
>
>> Bill
>>
>>
>> _______________________________________________
>> Pharo-project mailing list
>> Pharo-project(a)lists.gforge.inria.fr
>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
>>
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
> _______________________________________________
> Pharo-project mailing list
> Pharo-project(a)lists.gforge.inria.fr
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________
Pharo-project mailing list
Pharo-project(a)lists.gforge.inria.fr
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Oct. 24, 2009