Real closures
Klaus D. Witzel
klaus.witzel at cobss.com
Sun Oct 8 08:11:23 UTC 2006
On Sun, 08 Oct 2006 08:46:11 +0200, J J wrote:
> Klaus,
>
> I noticed in the comment (thanks for pointing out the BlockClosure class
> btw) it mentioned recompiling the whole image using the BlockClosure
> class instead of the BlockContext. Has this been tried? Any guess what
> the speed hit would be?
Not easy to predict. Here are areas that I've investigated:
1] instVar access; time(bytecode) versus: time(#instVarAt); assumption:
time(VM,tempVar access) = time(VM,instVar access)
[|required|required]bench '1.88744451109778e6 per second.'
[|required|thisContext instVarAt:1]bench '1.37969322947873e6 per second.'
Cost increase: > 30%
2] # of blocks affected by instVar access; depends on what your image
currently runs
BlockContext allInstances inject: 0 into: [:accum :each | each
hasInstVarRef ifTrue: [accum + 1] ifFalse: [accum]]
=> 113
3] list of blocks with instVar access (see report below); ignore duplicate
entries; seems that nothing much in the list looks time critical (except
that the performance of the compiler, which is part of the list, for me
counts as time critical ;-)
4] but the new music will play for those blocks which cannot be inlined by
the new compiler, and figures in terms of before/after are not easy to
obtain; except for a static cost analysis.
For the latter, both the new block valuation messages
(BlockClosure>>#value and friends) and the frequency of #createBlock:
versus: #blockCopy: are relevant; the bytecode access of temps is
invariant-again the assumption that time(VM,tempVar access) =
time(VM,instVar access). This paragraph is preliminary; I have as yet not
thought about the cost of the implementation of ClosureEnvironment and of
BlockClosure's non-local returns.
/Klaus
-------------------
|coll| coll := OrderedCollection new.
BlockContext allInstancesDo: [:each | each hasInstVarRef ifTrue: [coll
add: each]].
coll do:[:each | Transcript cr; show: each printString]
=>
[] in WorldState>>displayWorld:submorphs: {[worldDamageRects := self
drawWorld: aWorld submorphs: submorphs ...]}
[] in MenuItemMorph>>invokeWithEvent: {[(selArgCount := selector numArgs)
= 0 ifTrue: [target perform: selector] ...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in MenuItemMorph>>invokeWithEvent: {[(selArgCount := selector numArgs)
= 0 ifTrue: [target perform: selector] ...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in SystemWindow(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in AlignmentMorph(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in MenuItemMorph>>invokeWithEvent: {[(selArgCount := selector numArgs)
= 0 ifTrue: [target perform: selector] ...]}
[] in WorldState>>displayWorld:submorphs: {[worldDamageRects := self
drawWorld: aWorld submorphs: submorphs ...]}
[] in CornerRounder>>tweakCornersOf:on:in:borderWidth:corners: {[:i |
corner := corners at: i. saveBits := underBits at: i. saveBits if...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in SystemWindow(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in SystemWindow(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in ImageMorph(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in MenuItemMorph>>invokeWithEvent: {[(selArgCount := selector numArgs)
= 0 ifTrue: [target perform: selector] ...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in MessageSet>>selectedMessage {[:class :selector | class ifNil: [^
'Class vanished']. selector first is...]}
[] in Parser>>parse:class:noPattern:context:notifying:ifFail: {[:ex |
repeatNeeded := (requestor isKindOf: TextMorphEditor) not. myStream...]}
[] in MenuItemMorph>>invokeWithEvent: {[(selArgCount := selector numArgs)
= 0 ifTrue: [target perform: selector] ...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in ScrollBar>>menuButtonMouseDown: {[:sel | menuSelector := sel.
model perform: sel with: event]}
[] in MenuMorph(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in SystemWindow(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in AlignmentMorph(Morph)>>fullBounds {[:ex | fullBounds := bounds. ex
pass]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in Delay>>schedule {[beingWaitedOn := true. resumptionTime := Time
millisecondClockValue + dela...]}
[] in SharedQueue>>nextPut: {[writePosition > contentsArray size ifTrue:
[self makeRoomAtEnd]. content...]}
[] in SharedQueue>>nextPut: {[writePosition > contentsArray size ifTrue:
[self makeRoomAtEnd]. content...]}
[] in SharedQueue>>next {[readPosition = writePosition ifTrue: [self
error: 'Error in SharedQueue s...]}
[] in SharedQueue>>next {[readPosition = writePosition ifTrue: [self
error: 'Error in SharedQueue s...]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in Parser>>parse:class:noPattern:context:notifying:ifFail: {[:ex |
repeatNeeded := (requestor isKindOf: TextMorphEditor) not. myStream...]}
[] in Encoder>>init:context:notifying: {[:variable | node := VariableNode
new name: variable index: (n := n...]}
[] in Encoder>>lookupInPools:ifFound: {[:sym | (class bindingOf: sym)
ifNotNilDo: [:assoc | assocBlock value...]}
[] in Parser(Scanner)>>xDigit {[Number readFrom: source]}
[] in Encoder>>lookupInPools:ifFound: {[:sym | (class bindingOf: sym)
ifNotNilDo: [:assoc | assocBlock value...]}
[] in WeakSet>>growTo: {[:each | (each == flag or: [each == nil])
ifFalse: [self noCheckAdd: ea...]}
[] in Encoder>>lookupInPools:ifFound: {[:sym | (class bindingOf: sym)
ifNotNilDo: [:assoc | assocBlock value...]}
[] in Parser(Scanner)>>xDigit {[Number readFrom: source]}
[] in MethodNode>>generateWith:using: {[:m | method := m. method
properties: properties. ^ method]}
[] in BlockNode>>sizeForValue: {[:arg | size := size + (arg
sizeForStorePop: encoder)]}
[] in Encoder>>tempNames {[:node | (node isMemberOf: MessageAsTempNode)
ifTrue: [scopeTable keyAtVal...]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in WorldState>>displayWorld:submorphs: {[worldDamageRects := self
drawWorld: aWorld submorphs: submorphs ...]}
[] in WorldState>>displayWorld:submorphs: {[worldDamageRects := self
drawWorld: aWorld submorphs: submorphs ...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in Parser>>parse:class:noPattern:context:notifying:ifFail: {[:ex |
repeatNeeded := (requestor isKindOf: TextMorphEditor) not. myStream...]}
[] in TextMorphForEditView(TextMorph)>>keyStroke: {[editor readKeyboard]}
[] in Parser>>parse:class:noPattern:context:notifying:ifFail: {[:ex |
repeatNeeded := (requestor isKindOf: TextMorphEditor) not. myStream...]}
[] in EventSensor>>eventTickler {[delay wait. delta := Time
millisecondClockValue - lastEventPoll. (delta <...]}
[] in Encoder>>lookupInPools:ifFound: {[:sym | (class bindingOf: sym)
ifNotNilDo: [:assoc | assocBlock value...]}
[] in Parser>>removeUnusedTemps {[:temp | (UIManager default
chooseFrom: #('yes' 'no' ) title: ((temp ,...]}
[] in MethodNode>>generateWith:using: {[:m | method := m. method
properties: properties. ^ method]}
[] in BlockNode>>sizeForValue: {[:arg | size := size + (arg
sizeForStorePop: encoder)]}
[] in BlockNode>>sizeForValue: {[:arg | size := size + (arg
sizeForStorePop: encoder)]}
[] in Encoder>>tempNames {[:node | (node isMemberOf: MessageAsTempNode)
ifTrue: [scopeTable keyAtVal...]}
More information about the Squeak-dev
mailing list
|