[squeak-dev] The Trunk: System-ct.1367.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Jul 9 18:55:53 UTC 2022

Christoph Thiede uploaded a new version of System to project The Trunk:

==================== Summary ====================

Name: System-ct.1367
Author: ct
Time: 9 July 2022, 8:55:09.082532 pm
UUID: 5a63f39b-5c50-0140-b457-6c972adb1874
Ancestors: System-mt.1366

Merges accelerateUserInterfaceTheme:
	Accelerates property accesses to UserInterfaceTheme. This is done by changing the dictionary layout and representing keys as Arrays instead of Associations to improve the hash distribution. The postscript will automatically convert all UserInterfaceTheem subinstances.

	Use #atomicUpdate: in postscript.

This speeds up theme requests by >3750% and even speeds up common toolbuilding workloads by ~48% (see benchmarks below).

Thanks to Levente (ul) and Marcel (mt) for the review! For more information, see: http://lists.squeakfoundation.org/pipermail/squeak-dev/2022-May/220694.html


Detailed benchmarks and results from my machine:

I. Theme requests

	| theme random keys properties |
	theme := UserInterfaceTheme current.
	random := Random seed: 20220526.
	keys := theme properties keys sorted: [:key | ((key isKindOf: Association) ifTrue: [{key key. key value}] ifFalse: [key]) hash] ascending.
	properties := (1 to: 1000000) collect: [:i | keys atRandom: random].
	[properties do: [:ea | theme get: ea]] timeToRun.
	"Average of 8 runs:
		BEFORE: 3133.0 ms
		AFTER: 655.25 ms"

II. Toolbuilding workloads

	[ToolBuilder build: Browser] benchFor: 30 seconds.
	"Average of 3 runs:
		BEFORE: 19.4 ms
		AFTER: 13.1 ms"

=============== Diff against System-mt.1366 ===============

Item was changed:
  ----- Method: UserInterfaceTheme>>get: (in category 'private') -----
  get: keyObject 
  	"keyObject is intended to be an Association. We have two lookup strategies: 1) along the superclass chain *of the client*, 2) via a linked theme. Evaluate the result because there can be message sends stored or blocks."
  	| k |
  		at: keyObject
  		ifPresent: [:prop | ^ prop value].
+ 	keyObject isArray "simple key objects"
- 	keyObject isVariableBinding "simple key objects"
  		ifFalse: [^ self getViaLink: keyObject].
+ 	k := keyObject at: 1.
- 	k := keyObject key.
  	(self getViaSuperclasses: keyObject)
  		ifNotNil: [:prop | ^ prop].
+ 	keyObject at: 1 put: k. "restore"
- 	keyObject key: k. "restore"
  	^ self getViaLink: keyObject!

Item was changed:
  ----- Method: UserInterfaceTheme>>get:for: (in category 'private') -----
  get: propertySymbol for: scope
  	"For convenience. Does support access to non-class keys."
  	| aClass |
  	aClass := (scope isNil or: [scope isBehavior])
  		ifTrue: [scope]
  		ifFalse: [Smalltalk classNamed: scope].
+ 	aClass ifNotNil: [^ self get: {aClass. propertySymbol}].
- 	aClass ifNotNil: [^ self get: aClass -> propertySymbol].
+ 		at: {scope. propertySymbol}
- 		at: scope -> propertySymbol
  		ifPresent: [:prop | ^ prop value].
+ 	^ self getViaLink: {scope. propertySymbol}!
- 	^ self getViaLink: scope -> propertySymbol!

Item was changed:
  ----- Method: UserInterfaceTheme>>getViaSuperclasses: (in category 'private') -----
  getViaSuperclasses: keyObject 
  	"keyObject is intended to be an Association.
  	Find the superclass of the key of the keyObject (which will initially be the client's class) and make a new keyObject using that and the original message name, then try searching for that."
  	"We know we're the only referencer of keyObject.  Update it rather than create new ones, for performance reasons."
+ 	keyObject at: 1 put: (keyObject at: 1) superclass.
- 	keyObject key: keyObject key superclass.
+ 	(keyObject at: 1) ifNil: [^ nil].
- 	keyObject key ifNil: [^ nil].
  		at: keyObject
  		ifPresent: [:prop | ^ prop value].
  	^ self getViaSuperclasses: keyObject!

Item was changed:
  ----- Method: UserInterfaceTheme>>set:for:to: (in category 'building') -----
  set: propertySymbol for: aClassOrSymbol to: valueObject
  	"Where aClass asks its userInterfaceTheme for propertySymbol, provide valueObject."
  	| aClass |
  	aClass := aClassOrSymbol isBehavior ifTrue: [aClassOrSymbol] ifFalse: [Smalltalk classNamed: aClassOrSymbol].
  	aClass ifNil: [^ self].
  	^ self atomicUpdate:
  		[ : props | | key |
+ 		key := {aClass. propertySymbol}.
- 		key := aClass -> propertySymbol.
  				[ props
  					removeKey: key
  					ifAbsent: [ "already cleared, don't error" ] ]
  				[ props
  					at: key
  					put: valueObject ] ]!

Item was changed:
  ----- Method: UserInterfaceThemeRequest>>doesNotUnderstand: (in category 'lookup') -----
  doesNotUnderstand: aMessage 
  	"Look up the visual attribute specified by aMessage's #selector in the current theme for the current target object."
  	aMessage numArgs = 0 ifTrue: [
+ 		^ (self theme get: {self target class. aMessage selector})
- 		^ (self theme get: self target class -> aMessage selector)
  			ifNil: [(self theme respondsTo: aMessage selector)
  				ifTrue: [self theme perform: aMessage selector]
  				ifFalse: [nil "unset property"]]].
  	aMessage numArgs = 1 ifTrue: [
  		^ self theme
+ 			set: {self target class. aMessage selector asSimpleGetter}
- 			set: self target class -> aMessage selector asSimpleGetter
  			to: aMessage arguments first].
  	^ self theme
  		perform: aMessage selector
  		withArguments: aMessage arguments.!

Item was changed:
+ (PackageInfo named: 'System') postscript: '"Update UserInterfaceTheme instances (System-ct.1367)"
+ UserInterfaceTheme allSubInstancesDo: [:theme |
+ 	theme atomicUpdate: [:props |
+ 		props copy keysAndValuesDo: [:key :value |
+ 			(key isKindOf: Association) ifTrue: [
+ 				props
+ 					removeKey: key;
+ 					at: {key key. key value} put: value]]]].'!
- (PackageInfo named: 'System') postscript: 'SystemNavigation initializeAuthors.. "Adds Eric Gade"'!

More information about the Squeak-dev mailing list