Recompile slows down the compiler

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Recompile slows down the compiler

Klaus D. Witzel
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...