Recompile slows down the compiler

Klaus D. Witzel klaus.witzel at cobss.com
Sat Oct 21 10:06:06 UTC 2006


A strange performance problem happens when methods which refer to "global"  
variables (classVars, for example) are recompiled *after* the variable in  
question is initialized to a *large* collection.

The sequence of message sends is

1) Parser>>variable
2) Encoder>>encodeVariable:sourceRange:ifUnknown:
3) Encoder>>global:name:

and a full trace is below. This example results in a #hash (1 to: 917632  
do: ... hashMultiply) of a SparseLargeTable(SequenceableCollection) for  
every occurence of the class variable in the source text.

The reason for this particular slowdown is the use of Association>>#hash  
which hashes its key xOr its value (and the latter is the *very* *large*  
collection).

Any suggestions? Wouldn't it be sufficient to use the name of the class  
var, instead of the literal variable (the association).

/Klaus

P.S. reproducible, for example by filing out a method of Unicode class  
which accesses the GeneralCategory variable, then opening a code browser  
on that file (I'm using the tools and settings of the current  
squeak-dev-41.image).

--------------------------

VM: Win32 - a SmalltalkImage
Image: Squeak3.9gamma [latest update: #7065]

SecurityManager state:
Restricted: false
FileAccess: true
SocketAccess: true
Working Dir ...\kWitzel\My Documents\SqueakDev
Trusted Dir ...\kWitzel\My Documents\SqueakDev\kWitzel
Untrusted Dir ...\My Squeak\kWitzel

SmallInteger>>hashMultiply
	Receiver: 37545126
	Arguments and temporary variables:
		low: 	nil
	Receiver's instance variables:
37545126

SparseLargeTable(SequenceableCollection)>>hash
	Receiver: a SparseLargeTable(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1  
1 1 1 1 1 1 1 1 1 1 29 21 2...etc...
	Arguments and temporary variables:
		hash: 	37545126
		i: 	670022
		iLimiT: 	917632
	Receiver's instance variables:
		base: 	1
		size: 	917632
		chunkSize: 	1024
		defaultValue: 	0

Association>>hash
	Receiver: #GeneralCategory->a SparseLargeTable(1 1 1 1 1 1 1 1 1 1 1 1 1  
1 1 1 1 1 1 1 1 1 1 1 1 1 1...etc...
	Arguments and temporary variables:

	Receiver's instance variables:
		key: 	#GeneralCategory
		value: 	a SparseLargeTable(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1  
1 1 1 1...etc...

Dictionary>>scanFor:
	Receiver: a Dictionary()
	Arguments and temporary variables:
		anObject: 	#GeneralCategory->a SparseLargeTable(1 1 1 1 1 1 1 1 1 1 1 1  
1 1 1 1 ...etc...
		element: 	nil
		start: 	nil
		finish: 	22
		index: 	nil
		indexLimiT: 	nil
	Receiver's instance variables:
		tally: 	0
		array: 	#(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil  
nil nil ni...etc...


--- The full stack ---
SmallInteger>>hashMultiply
SparseLargeTable(SequenceableCollection)>>hash
Association>>hash
Dictionary>>scanFor:
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dictionary(Set)>>findElementOrNil:
Dictionary>>at:ifAbsent:
Encoder>>name:key:class:type:set:
Encoder>>global:name:
[] in Encoder>>encodeVariable:sourceRange:ifUnknown: {[:assoc | varNode :=  
self global: assoc name: name]}
[] in Encoder>>lookupInPools:ifFound: {[:assoc |  assocBlock value:  
assoc.  ^ true]}
Association(Object)>>ifNotNilDo:
[] in Encoder>>lookupInPools:ifFound: {[:sym |  (class bindingOf: sym)    
ifNotNilDo: [:assoc |     assocBlock value...]}
Symbol class>>hasInterned:ifTrue:
Encoder>>lookupInPools:ifFound:
[] in Encoder>>encodeVariable:sourceRange:ifUnknown: {[(self     
lookupInPools: name    ifFound: [:assoc | varNode := self global: ...]}
Dictionary>>at:ifAbsent:
Encoder>>encodeVariable:sourceRange:ifUnknown:
Parser>>variable
Parser>>primaryExpression
Parser>>expression
Parser>>primaryExpression
Parser>>messagePart:repeat:
Parser>>expression
Parser>>statements:innerBlock:
Parser>>method:context:encoder:
[] in Parser>>parse:class:noPattern:context:notifying:ifFail: {[methNode  
:= self     method: noPattern     context: ctxt     encoder: (Enco...]}
BlockContext>>on:do:
Parser>>parse:class:noPattern:context:notifying:ifFail:
Compiler>>format:noPattern:ifFail:
Compiler>>format:in:notifying:decorated:
Compiler class>>format:in:notifying:decorated:
[] in PrettyTextDiffBuilder>>split: {[sourceClass prettyPrinterClass    
format: trimmed   in: sourceClass   notify...]}
BlockContext>>on:do:
PrettyTextDiffBuilder>>split:
PrettyTextDiffBuilder(TextDiffBuilder)>>sourceString:
PrettyTextDiffBuilder(TextDiffBuilder)>>from:to:
PrettyTextDiffBuilder class>>from:to:inClass:
TextDiffBuilder class>>buildDisplayPatchFrom:to:inClass:prettyDiffs:
[] in FileContentsBrowser>>methodDiffFor:class:selector:meta:  
{[TextDiffBuilder   buildDisplayPatchFrom: source   to: aString   inClass:  
th...]}
BlockContext>>ensure:
CursorWithMask(Cursor)>>showWhile:
FileContentsBrowser>>methodDiffFor:class:selector:meta:
FileContentsBrowser>>extraInfo
FileContentsBrowser>>infoViewContents
PluggableTextMorph>>getText
PluggableTextMorph>>update:
[] in FileContentsBrowser(Object)>>changed: {[:aDependent | aDependent  
update: aParameter]}
DependentsArray>>do:
FileContentsBrowser(Object)>>changed:
FileContentsBrowser>>updateInfoView
FileContentsBrowser>>contents
PluggableShoutMorph(PluggableTextMorph)>>getText
PluggableShoutMorph(PluggableTextMorph)>>update:
[] in FileContentsBrowser(Object)>>changed: {[:aDependent | aDependent  
update: aParameter]}
DependentsArray>>do:
FileContentsBrowser(Object)>>changed:
FileContentsBrowser(Object)>>contentsChanged
FileContentsBrowser(CodeHolder)>>contentsChanged
...etc...




More information about the Squeak-dev mailing list