[squeak-dev] The Trunk: System-bf.510.mcz

commits at source.squeak.org commits at source.squeak.org
Mon Jan 7 13:56:50 UTC 2013


Bert Freudenberg uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-bf.510.mcz

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

Name: System-bf.510
Author: bf
Time: 7 January 2013, 2:54:18.48 pm
UUID: 616a0bcd-db64-413a-a55a-4a0f55f7ad97
Ancestors: System-nice.509

Wouldn't it be useful to know how old an object is? In our images there are objects that were created more than 30 years ago, after all. With this, we will know when objects were created, starting from today. See ObjectHistory's class comment for details.

=============== Diff against System-nice.509 ===============

Item was added:
+ ----- Method: Object>>oopAge (in category '*system-support') -----
+ oopAge
+ 	^ ObjectHistory current ageOf: self!

Item was added:
+ ----- Method: Object>>oopTimestamp (in category '*system-support') -----
+ oopTimestamp
+ 	^ ObjectHistory current timestampOf: self!

Item was added:
+ Object subclass: #ObjectHistory
+ 	instanceVariableNames: 'marks markProcess'
+ 	classVariableNames: 'Current'
+ 	poolDictionaries: ''
+ 	category: 'System-Support'!
+ 
+ !ObjectHistory commentStamp: 'bf 11/16/2012 12:19' prior: 0!
+ ObjectHistory holds ObjectHistoryMark objects which are placed in the object memory at regular intervals by its markProcess in the background. Adjacent marks (with no remaining objects inbetween) are coalesced so over time the collection does not grow unnecessarily large.
+ 
+ Using these markers it is possible to determine the age of objects in memory from the time the ObjectHistory was initialized. Try e.g.:
+ 	self oopTimestamp.	
+ 	self oopAge.
+ 	ObjectHistory current oopClassesByDate.
+ 
+ Instance Variables
+ 	marks:		SortedCollection of ObjectHistoryMark objects
+ 	markProcess:		a Process running our markLoop
+ !

Item was added:
+ ----- Method: ObjectHistory class>>current (in category 'accessing') -----
+ current
+ 	^ Current ifNil: [Current := self new]!

Item was added:
+ ----- Method: ObjectHistory class>>initialize (in category 'class initialization') -----
+ initialize
+ 	self current.
+ !

Item was added:
+ ----- Method: ObjectHistory>>ageOf: (in category 'queries') -----
+ ageOf: anObject
+ 	"Age of anObject in seconds"
+ 	| timestamp |
+ 	timestamp := self timestampOf: anObject.
+ 	timestamp ifNil: [^0].
+ 	^(DateAndTime now - timestamp) asSeconds roundTo: self markRate!

Item was added:
+ ----- Method: ObjectHistory>>initialize (in category 'initializing') -----
+ initialize
+ 	self restartMarkProcess.
+ 
+ !

Item was added:
+ ----- Method: ObjectHistory>>markLoop (in category 'marking') -----
+ markLoop
+ 	[true] whileTrue: [
+ 		self markUpdate.
+ 		(Delay forSeconds: self markRate) wait]!

Item was added:
+ ----- Method: ObjectHistory>>markRate (in category 'marking') -----
+ markRate
+ 	"rate of creating ObjectHistoryMarks"
+ 	^60!

Item was added:
+ ----- Method: ObjectHistory>>markUpdate (in category 'marking') -----
+ markUpdate
+ 	"Add a new mark and compact the marks collection"
+ 	| mark prev |
+ 	"lazy init so this happens in the background process"
+ 	marks ifNil: [self reinitMarks].
+ 	"add new mark to object memory"
+ 	mark := self newMark.
+ 	mark timestamp <= marks last timestamp ifTrue: [^self "could happen if clock is wrong"].
+ 	marks addLast: mark.
+ 	"compact the table by removing adjacent marks"
+ 	prev := marks first.
+ 	marks removeAllSuchThat: [:each | | doDelete |
+ 		doDelete := prev objectAfter == each.
+ 		prev := each.
+ 		doDelete].
+ 	"The loop above is O(n) in number of marks, but that number should never become so large to be an issue. Even if the number was large, this is running at system background priority so should not interfere with any user process, not even user background processes. The symptom should only be that the system is less idle.
+ 	
+ 	If we ever get to a point where the number of marks is an issue then the compacting here could be made partial: since old marks rarely get coalesced it would make sense to only check the newer ones often, and the old ones perhaps only at the system startup."!

Item was added:
+ ----- Method: ObjectHistory>>newMark (in category 'private') -----
+ newMark
+ 	^ ObjectHistoryMark new!

Item was added:
+ ----- Method: ObjectHistory>>oopClassesByAge (in category 'stats') -----
+ oopClassesByAge
+ 	"Answer collection of (oopAge in seconds -> sorted counts of object classes) sorted from lowest age"
+ 	"ObjectHistory current oopClassesByAge"
+ 
+ 	| stats prev endOfMemory now bag age obj |
+ 	endOfMemory := Object new.
+ 	stats := OrderedCollection new: 1000.
+ 	prev := nil.
+ 	now := self newMark timestamp.
+ 	marks do: [:mark |
+ 		prev ifNotNil: [
+ 			bag := Bag new.
+ 			obj := prev objectAfter.
+ 			[obj == mark] whileFalse: [
+ 				bag add: obj class.
+ 				obj := obj nextObject.
+ 				obj == endOfMemory ifTrue: [self error: 'should not happen']].
+ 			age := (now - mark timestamp) asSeconds roundTo: self markRate.
+ 			stats addFirst: age -> bag sortedCounts].
+ 		prev := mark].
+ 	^ stats
+ !

Item was added:
+ ----- Method: ObjectHistory>>oopClassesByDate (in category 'stats') -----
+ oopClassesByDate
+ 	"Answer collection of (Date -> sorted counts of object classes) sorted from newest date"
+ 	"ObjectHistory current oopClassesByDate"
+ 
+ 	| stats prev endOfMemory bag date obj thisDate |
+ 	endOfMemory := Object new.
+ 	stats := OrderedCollection new: 1000.
+ 	prev := nil.
+ 	thisDate := nil.
+ 	bag := Bag new.
+ 	marks do: [:mark |
+ 		prev ifNotNil: [
+ 			obj := prev objectAfter.
+ 			[obj == mark] whileFalse: [
+ 				bag add: obj class.
+ 				obj := obj nextObject.
+ 				obj == endOfMemory ifTrue: [self error: 'should not happen']].
+ 			date := mark timestamp asDate.
+ 			thisDate = date ifFalse: [
+ 				stats addFirst: date -> bag sortedCounts.
+ 				bag := Bag new.
+ 				thisDate := date]].
+ 		prev := mark].
+ 	thisDate = date ifFalse: [
+ 		stats addLast: date -> bag sortedCounts].
+ 	^ stats
+ !

Item was added:
+ ----- Method: ObjectHistory>>oopCountsByAge (in category 'stats') -----
+ oopCountsByAge
+ 	"Answer collection of (oopAge in seconds -> number of objects) sorted from lowest age"
+ 	"ObjectHistory current oopCountsByAge"
+ 
+ 	| stats prev endOfMemory now n age obj |
+ 	endOfMemory := Object new.
+ 	stats := OrderedCollection new: 1000.
+ 	prev := nil.
+ 	now := self newMark timestamp.
+ 	marks do: [:mark |
+ 		prev ifNotNil: [
+ 			n := 0.
+ 			obj := prev objectAfter.
+ 			[obj == mark] whileFalse: [
+ 				n := n + 1.
+ 				obj := obj nextObject.
+ 				obj == endOfMemory ifTrue: [self error: 'should not happen']].
+ 			age := (now - mark timestamp) asSeconds roundTo: self markRate.
+ 			stats addFirst: age -> n].
+ 		prev := mark].
+ 	^ stats
+ !

Item was added:
+ ----- Method: ObjectHistory>>reinitMarks (in category 'private') -----
+ reinitMarks
+ 	marks := ObjectHistoryMark allInstances asOrderedCollection.
+ 	marks
+ 		ifEmpty: [marks add: self newMark]
+ 		ifNotEmpty: [ | prev |
+ 			prev := nil.
+ 			marks removeAllSuchThat: [:obj |
+ 				prev notNil and: [prev timestamp >= obj timestamp]]].
+ !

Item was added:
+ ----- Method: ObjectHistory>>restartMarkProcess (in category 'marking') -----
+ restartMarkProcess
+ 	markProcess ifNotNil: [markProcess terminate].
+ 	markProcess := [self markLoop]
+ 		forkAt: Processor systemBackgroundPriority
+ 		named: 'ObjectHistory''s markProcess'.
+ !

Item was added:
+ ----- Method: ObjectHistory>>timestampOf: (in category 'queries') -----
+ timestampOf: anObject
+ 	"Timestamp of anObject, or nil if too new"
+ 	| endOfMemory mark |
+ 	anObject class == SmallInteger ifTrue: [^nil].
+ 	mark := anObject.
+ 	endOfMemory := Object new.
+ 	[mark class == ObjectHistoryMark] whileFalse: [
+ 		mark := mark nextObject.
+ 		mark == endOfMemory ifTrue: [^nil]].
+ 	^mark timestamp!

Item was added:
+ Object subclass: #ObjectHistoryMark
+ 	instanceVariableNames: 'timestamp'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'System-Support'!
+ 
+ !ObjectHistoryMark commentStamp: 'bf 11/7/2012 00:12' prior: 0!
+ An ObjectHistoryMark is a permanent mark in the object memory. It holds a timestamp.
+ 
+ While the timestamp could be used directly as mark by ObjectHistory, it's conceivable that its format might change in the future, and we do not want the mark's relative position in memory to change (which would be the case if it was migrated to a new format). So we use a distinct object instead (and we protect it against accidental become-ing by overriding those methods).!

Item was added:
+ ----- Method: ObjectHistoryMark>>become: (in category 'mutating') -----
+ become: otherObject
+ 	^self error: 'marks need to stay fixed in the object memory'!

Item was added:
+ ----- Method: ObjectHistoryMark>>becomeForward: (in category 'mutating') -----
+ becomeForward: otherObject
+ 	^self error: 'marks need to stay fixed in the object memory'!

Item was added:
+ ----- Method: ObjectHistoryMark>>initialize (in category 'initialization') -----
+ initialize
+ 	timestamp := DateAndTime now.
+ 	timestamp instVarNamed: #nanos put: 0.
+ !

Item was added:
+ ----- Method: ObjectHistoryMark>>objectAfter (in category 'accessing') -----
+ objectAfter
+ 	"Answer the next object in memory after me and my timestamp"
+ 	| successor |
+ 	successor := self nextObject.
+ 	successor == timestamp
+ 		ifTrue: [successor := successor nextObject].
+ 	^ successor!

Item was added:
+ ----- Method: ObjectHistoryMark>>printOn: (in category 'printing') -----
+ printOn: aStream
+ 	aStream
+ 		nextPutAll: self class name;
+ 		nextPut: $(;
+ 		print: timestamp;
+ 		nextPut: $)!

Item was added:
+ ----- Method: ObjectHistoryMark>>timestamp (in category 'accessing') -----
+ timestamp
+ 	^timestamp
+ !



More information about the Squeak-dev mailing list