GC in Smalltalk - Now What?

53
GC in Smalltalk now what? Javier Burroni gera

description

ESUG 2011, Edinburgh

Transcript of GC in Smalltalk - Now What?

Page 1: GC in Smalltalk - Now What?

GC in Smalltalknow what?

Javier Burroni gera

Page 2: GC in Smalltalk - Now What?

Smalltalk VMWriten in Smalltalk

.exe / .dll generationJITMessage dispatchingObject formatMemory management

Object creation / copyGCBecome

PrimitivesFFIProcessesCallbacksetc

Page 3: GC in Smalltalk - Now What?

What now?

Optimizations

Finish the VM (of course)

Alternative GC

Instrumentation

Page 4: GC in Smalltalk - Now What?

Optimizations

Monomorphic Inline Cache

Linked sends

Inline Underprimitives

Replace primitives

Many others with small impact

Page 5: GC in Smalltalk - Now What?

currentClass := currentClass superclass

Object >> #isNilcurrentClass == Object

^false

UndefinedObject >> #isNilcurrentClass == UndefinedObject

^true

self _isSmallInteger

^false

Optimization: Linked send

currentClass := self class

Page 6: GC in Smalltalk - Now What?

currentClass := currentClass superclass

Object >> #isNilcurrentClass == Object

^false

UndefinedObject >> #isNilcurrentClass == UndefinedObject

^true

self _isSmallInteger

^false

Optimization: Linked send

currentClass := self class

Page 7: GC in Smalltalk - Now What?

Optimization: Linked send

for: aClass renderJumpTo: aCompiledMethod| reference |self disableCode: [assembler breakpoint].assembler

compareTempToConstant: aClass methodDictionaries oop;absoluteReferenceTo: aClass methodDictionaries;nearJumpIfEqual.

reference := assembler relativeReferenceTo: aCompiledMethod fullName.reference noClassCheck.

Object subclass: #SelectorMultiplexorNativizer

Page 8: GC in Smalltalk - Now What?

Optimization: Linked send

for: aClass renderJumpTo: aCompiledMethod| reference nextImplementation |self disableCode: [assembler breakpoint].nextImplementation := assembler

compareTempToConstant: aClass methodDictionaries oop;absoluteReferenceTo: aClass methodDictionaries;shortJumpIfNotEqual.

self emitMonomorphicInlineCacheTo: aCompiledMethod.

assembler nearJump.reference := assembler relativeReferenceTo: aCompiledMethod fullName.reference noClassCheck.assembler jumpDestinationFor: nextImplementat

Object subclass: #SelectorMultiplexorNativizer

Page 9: GC in Smalltalk - Now What?

Optimization: Linked send

for: aClass renderJumpTo: aCompiledMethod| reference nextImplementation skipMic |self disableCode: [assembler breakpoint].nextImplementation := assembler

compareTempToConstant: aClass methodDictionaries oop;absoluteReferenceTo: aClass methodDictionaries;shortJumpIfNotEqual.

skipMic := assembler compareArg; assembler shortJumpIfEqual.self emitMonomorphicInlineCacheTo: aCompiledMethod.assembler jumpDestinationFor: skipMic.assembler nearJump.reference := assembler relativeReferenceTo: aCompiledMethod fullName.reference noClassCheck.assembler jumpDestinationFor: nextImplementat

Object subclass: #SelectorMultiplexorNativizer

Page 10: GC in Smalltalk - Now What?

Optimization: Linked send

emitMonomorphicInlineCacheTo: aCompiledMethodassembler

loadEntrypoint: aCompiledMethod;patchClassCheck;patchCallSite

Object subclass: #SelectorMultiplexorNativizer

Page 11: GC in Smalltalk - Now What?

Optimization: Linked send

GenerationalGC>>#collectself initLocals;

...purgeRoots;followCodeCacheReferences;followRoots;followStack;...

call near ptr gc_purgeRootsmov eax, [esp]call near ptr gc_followCodeCacheReferencesmov eax, [esp]call near ptr gc_followRootsmov eax, [esp]call near ptr gc_followStackmov eax, [esp]call near ptr gc_rescueEphemerons

Page 12: GC in Smalltalk - Now What?

Optimization: Linked send

GenerationalGC>>#collectself initLocals;

...purgeRoots;followCodeCacheReferences;followRoots;followStack;...

call near ptr gc_GenerationalGC__purgeRoots mov eax, [esp] call near ptr gc_GenerationalGC__followCodeCacheReferences mov eax, [esp] call near ptr gc_GenerationalGC__followRoots mov eax, [esp] call near ptr gc_VMGarbageCollector__followStack mov eax, [esp] call near ptr gc_VMGarbageCollector__rescueEphemerons

Page 13: GC in Smalltalk - Now What?

_primitives (under primitives)

assembleUnrotateassembler rotate: 8

assembleIsSmallInteger| integer nonInteger |integer := assembler testAndJumpIfInteger.nonInteger := assembler loadConstant: false oop; shortJump.assembler

jumpDestinationFor: integer;loadConstant: true oop;jumpDestinationFor: nonInteger

SmalltalkBytecode subclass: #ExtensionBytecode

Page 14: GC in Smalltalk - Now What?

Optimization: Inlining _primitives

MarkAndCompactGC>>#setNewPositions: space....

[headerBits := reference _basicAt: 1.reference _basicAt: 1 put: newPosition _toObject.nextReference := headerBits _unrotate.nextReference _isSmallInteger]whileFalse: [reference := nextReference].

...

mov eax, [ecx+4] call near ptr gc_unrotate mov [ebp-18], eax mov eax, [ebp-18] call near ptr gc_isSmallInteger

Page 15: GC in Smalltalk - Now What?

Optimization: Inlining _primitives

mov eax, [ecx+4] rol eax, 8 ; assembler rotate: 8. mov [ebp-18h], eax mov eax, [ebp-18h] test al, 1 jnz short integer ; assembler testAndJumpIfInteger. mov eax, offset false ; assembler loadConstant: false oop; jmp notInteger ; shortJump. mov eax, offset true ; assembler loadConstant: true oop.

MarkAndCompactGC>>#setNewPositions: space....

[headerBits := reference _basicAt: 1.reference _basicAt: 1 put: newPosition _toObject.nextReference := headerBits _unrotate.nextReference _isSmallInteger]whileFalse: [reference := nextReference].

...

Page 16: GC in Smalltalk - Now What?

Optimization: Inlining _primitives

assembleselector := methodNativizer compiledMethod selectorAt: literalNumber.^self mustInline

ifTrue: [self inlineUnderPrimitive]ifFalse: [super assemble]

inlineUnderPrimitive^(ExtensionBytecode for: selector using: assembler) assemble

SendSelectorBytecode subclass: #UnderPrimitiveSendBytecode

ExtensionBytecode >> #assembleUnrotateassembler rotate: 8

Page 17: GC in Smalltalk - Now What?

Optimization: replaced primitives

at: index^contents _basicAt: index + 1

add: object| position |position := self nextFree.position >= contents _size ifTrue: [self grow].self

nextFree: position + 1;at: position put: object

at: index^contents at: index + 1

add: object| position |position := self nextFree.position >= contents size ifTrue: [self grow].self

nextFree: position + 1;at: position put: object

VMArray

Page 18: GC in Smalltalk - Now What?

Instrumenting the GC

Stats (simple) examples:

Max graph depth

Coefficient of Stability

Object size histogram

Page 19: GC in Smalltalk - Now What?

Instrumenting the GC“simple” example

MarkAndCompactGC >> #compact: spaceself objectsFrom: space base to: space nextFree do: [:object |

object _hasBeenSeenInSpace ifTrue: [| moved size |size := object _byteSize // 4 + 1.size > 1024 ifTrue: [size := 1025].stats at: size put: (stats at: size) + 1.moved := auxSpace shallowCopy: object.moved _beUnseenInSpace]]

Page 20: GC in Smalltalk - Now What?

Instrumenting the GC“simple” example

MarkAndCompactGC >> #stats: iWantAnyArray| answer |self loadSpaces.answer := oldSpace shallowCopy: stats contents.answer _basicAt: 0 put: (iWantAnyArray _basicAt: 0).answer _beUnseenInSpace.self saveSpaces.^answer

MarkAndCompactGC >> #currentStats: iWantAnyArray^Current stats: iWantAnyArray

Page 21: GC in Smalltalk - Now What?

Instrumenting the GCstats how to

Object subclass: #StatisticsAnalyzerinstanceVariableNames: 'harvester'

Object subclass: #StatisticsHarvesterinstanceVariableNames: 'contents'

Page 22: GC in Smalltalk - Now What?

VMBuilder>>#buildAndInstallMarkAndCompact...statisticsSpace := GCSpace externalNew: 1024 * 1024 * 4.gc statisticsOn: statisticsSpace.StatisticsHarvester currentContents: gc statisticsContents....

statisticsSpace: shared between the GC and the image

Instrumenting the GCstats how to

Page 23: GC in Smalltalk - Now What?

Object subclass: #VMGarbageCollector

initialize...statistics := VMArray new.harvester := StatisticsHarvester new

Instrumenting the GCstats how to

Page 24: GC in Smalltalk - Now What?

Object subclass: #VMGarbageCollector

statisticsOn: spacestatistics on: space; emptyReserving: 1000.harvester on: statistics....

Instrumenting the GCstats how to

Page 25: GC in Smalltalk - Now What?

LiteralNativizer class instanceVariableNames: ' ClassesToFreeze'

initializeClassesToFreezeClassesToFreeze := (OrderedCollection new: 10)

add: VMGarbageCollector;add: VMArray;add: GCSpace;add: GCSpaceInfo;add: ExternalAddress;add: SLLInfo;add: ResidueObject;add: SpaceStatisticsHarvester;asArray

Instrumenting the GCstats how to

Page 26: GC in Smalltalk - Now What?

initializeClassesToFreezeClassesToFreeze := (OrderedCollection new: 10)

add: VMGarbageCollector;add: VMArray;add: GCSpace;add: GCSpaceInfo;add: ExternalAddress;add: SLLInfo;add: ResidueObject;add: SpaceStatisticsHarvester;asArray

Instrumenting the GCstats how to

LiteralNativizer class instanceVariableNames: ' ClassesToFreeze'

Page 27: GC in Smalltalk - Now What?

Instrumenting the GCstability stats

Stable

Compacted

First moved object

A high stability coefficient implies a high level of stability in the oldSpace.The converse is not necessarily true

stability"%" := firstMoved offset / oldSpace size

Page 28: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

compact: spaceself objectsFrom: space base to: space nextFree do: [:object |

object _hasBeenSeenInSpace ifTrue: [| moved |moved := auxSpace shallowCopy: object.moved == object ifTrue: [ harvester firstMoved: object].moved _beUnseenInSpace]]

Instrumenting the GCstability stats

Page 29: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

compact: spaceself objectsFrom: space base to: space nextFree do: [:object |

object _hasBeenSeenInSpace ifTrue: [| moved |moved := auxSpace shallowCopy: object.moved == object ifTrue: [ harvester firstMoved: object].moved _beUnseenInSpace]]

Instrumenting the GCstability stats

Page 30: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

decommitSlackoldSpace decommitSlack.harvester oldSpace: oldSpace

Instrumenting the GCstability stats

Page 31: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

decommitSlackoldSpace decommitSlack.harvester oldSpace: oldSpace

Instrumenting the GCstability stats

Page 32: GC in Smalltalk - Now What?

Object subclass: #StatisticsHarvester

oldSpace: spacecontents

at: 1 put: space base;at: 2 put: space nextFree

Instrumenting the GCstability stats

Page 33: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

follow: root count: size startingAt: base[

... harvester graphDepth: stack size.stack isEmpty]whileFalse: [

limit := stack pop.index := stack pop.objects := stack pop]

Instrumenting the GCgraph depth stats

Page 34: GC in Smalltalk - Now What?

VMGarbageCollector subclass: #MarkAndCompactGC

follow: root count: size startingAt: base[

...stack isEmpty]whileFalse: [

harvester graphDepth: stack size.limit := stack pop.index := stack pop.objects := stack pop]

Instrumenting the GCgraph depth stats

Page 35: GC in Smalltalk - Now What?

Instrumenting the GCgraph depth stats

Object subclass: #StatisticsHarvester

graphDepth: depthmaxGraphDepth < depth ifTrue: [

maxGraphDepth := depth.contents at: 4 put: maxGraphDepth]

Page 36: GC in Smalltalk - Now What?

Instrumenting the GC

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 350

0.2

0.4

0.6

0.8

1

1.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 354700

4750

4800

4850

4900

4950

5000

5050

5100

sta

bili

tys

tac

k d

ep

th

Page 37: GC in Smalltalk - Now What?

Alternate Scavenging algorithms

Z (leaf first?) scavenger15% fasterUses lots of memory

Queue based Breadth-first scavengingMark and compactGenerational

Cheney's algorithmOnly for generationalUses semi-spaces to maintain queue

Page 38: GC in Smalltalk - Now What?

Alternate Scavenging algorithms

GenerationalGC subclass: #QueuedGenerationalGC InstanceVariableNames: ' queue '

MarkAndCompactGC subclass: #QueuedMarkAndCompactGC InstanceVariableNames: ' queue '

GenerationalGC subclass: #CheneyGC instanceVariableNames: ' toBase oldBase '

MarkAndCompactGC subclass: #ZMarkAndCompactGC instanceVariableNames: ''

Page 39: GC in Smalltalk - Now What?

Alternate Scavenging algorithmstests

GenerationalGCTest subclass: #QueuedGenerationalGCTestgcClass

^QueuedGenerationalGC

MarkAndcompactGCTest subclass: #QueuedMarkAndCompactGCTestgcClass

^QueuedMarkAndCompactGC

GenerationalGCTest subclass: #CheneyGCTestgcClass

^QueuedGenerationalGC

MarkAndcompactGCTest subclass: #ZMarkAndCompactGCTestgcClass

^ZMarkAndCompactGC

Page 40: GC in Smalltalk - Now What?

Depth-first

GenerationalGC>>#follow: root count: size startingAt: base...

object _isProxyifTrue: [objects _basicAt: index put: object _proxee]ifFalse: [| moved |

stack push: limit; push: objects; push: index.moved := self moveToOldOrTo: object.objects _basicAt: index put: moved.self rememberIfWeak: moved.index := -1.limit := index + (self sizeToFollow: moved).objects := moved]]].

stack isEmpty]whileFalse: [

index := stack pop.objects := stack pop.limit := stack pop]

Page 41: GC in Smalltalk - Now What?

Z (leaf-first?)

QueuedGenerationalGC>>#follow: root count: size startingAt: base...

object _isProxyifTrue: [objects _basicAt: index put: object _proxee]ifFalse: [| moved |

moved := self moveToOldOrTo: object.objects _basicAt: index put: moved.self rememberIfWeak: moved.

stack push: moved ]]].

stack isEmpty]whileFalse: [

index := -1.objects := stack pop.limit := index + (self sizeToFollow: objects)]

Page 42: GC in Smalltalk - Now What?

Breadth-first

QueuedGenerationalGC>>#follow: root count: size startingAt: base...

object _isProxyifTrue: [objects _basicAt: index put: object _proxee]ifFalse: [| moved |

moved := self moveToOldOrTo: object.objects _basicAt: index put: moved.self rememberIfWeak: moved.

queue push: moved ]]].

queue isEmpty]whileFalse: [

index := -1.objects := queue popFirst.limit := index + (self sizeToFollow: objects)]

Page 43: GC in Smalltalk - Now What?

Cheney

CheneyGC>>#follow: root count: size startingAt: base...

object _isProxyifTrue: [objects _basicAt: index put: object _proxee]ifFalse: [| moved |

moved := self moveToOldOrTo: object.objects _basicAt: index put: moved.

]]].

Cheney, C. J. 1970. A nonrecursive list compacting algorithm. Communications of the ACM. 13, 11, 677-678.

Page 44: GC in Smalltalk - Now What?

Cheney

from to old

.

.

.

.

.

rembset

Page 45: GC in Smalltalk - Now What?

Cheney

from to old

.

.

.

.

.

rembset

Page 46: GC in Smalltalk - Now What?

Cheney

from to old

.

.

.

.

.

rembset

"Two three fingers scavenging”

Page 47: GC in Smalltalk - Now What?

Cheney

from to old

.

.

.

.

.

rembset

Page 48: GC in Smalltalk - Now What?

Cheney

followStacksuper followStack.self followAll

followRootssuper followRoots.self followAll

rescueEphemeron: ephemeronsuper rescueEphemeron: ephemeron.self followAll

Page 49: GC in Smalltalk - Now What?

Cheney

followAll[toBase < toSpace nextFree or: [oldBase < oldSpace nextFree]] whileTrue: [

toBase := self followAllFrom: toSpace using: toBase.oldBase := self followAllFrom: oldSpace using: oldBase]

GenerationalGC subclass: #CheneyGC instanceVariableNames: ' toBase oldBase '

"Two three fingers scavenging”

Page 50: GC in Smalltalk - Now What?

Cheney

GenerationalGC subclass: #CheneyGC instanceVariableNames: ' toBase oldBase '

loadSpacessuper loadSpaces.toSpace reset.toBase := toSpace base.oldBase := oldSpace nextFree

Page 51: GC in Smalltalk - Now What?

Cheney

followAllFrom: space using: scanBase| base |base := scanBase.[base < space nextFree] whileTrue: [| object |

object := (base + 8) _toObject.object _isExtended

ifTrue: [base := object _basicSize * 4 + base.object := base _toObject]

ifFalse: [base := base + 8].base := base + object _byteSize.self follow: object].

^base

Page 52: GC in Smalltalk - Now What?

What now?

.exe / .dll generationJITMessage dispatchingObject formatMemory management

Object creation / copyGCBecome

PrimitivesFFI

ProcessesCallbacksPublish paperJIT + Generational + MarkAndCompact

Page 53: GC in Smalltalk - Now What?

[Audience hasQuestions] whileTrue: [self answer: Audience nextQuestion].

Audience do: [:you | self thank: you].

self returnTo: Audience