'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 19 May 2009 at 11:03:49 am'!

!ProcessBrowser class methodsFor: 'CPU utilization' stamp: 'jmv 5/19/2009 10:01'!
dumpPigStackOn: aStream andClose: aBoolean
	| promise process depth stack suspendedContext |
	promise := Processor tallyCPUUsageFor: 1 every: 10.
	
	[ | tally |
	tally := promise value.
		"WorldState addDeferredUIMessage: [self dumpTallyOnTranscript: tally]" 
		process _ tally sortedCounts first value.
		(100.0 * (tally occurrencesOf: process) / tally size) rounded printOn: aStream.
		aStream
			nextPutAll: ' % ';
			nextPutAll: (process browserPrintStringWith: (ProcessBrowser nameAndRulesFor: process) first);
			cr.
		depth _ 20.
		stack _ process == Processor activeProcess
			ifTrue: [thisContext stackOfSize: depth]
			ifFalse: [suspendedContext _ process suspendedContext.
				suspendedContext
					ifNotNil: [suspendedContext stackOfSize: depth]].
		stack 
			ifNil: [ aStream nextPutAll: 'No context'; cr]
			ifNotNil: [
				stack do: [ :c | 
					c printOn: aStream.
					aStream cr]].
		aBoolean ifTrue: [aStream close].
	] fork! !


!SpaceTally methodsFor: 'fileOut' stamp: 'jmv 5/19/2009 10:23'!
printSpaceAnalysis	
	"SpaceTally new printSpaceAnalysis"

	| stream |
	stream _ FileStream newFileNamed: 'STspace.text'.
	[ self printSpaceAnalysis: 1 on: stream ] ensure: [ stream close ]! !

!SpaceTally methodsFor: 'fileOut' stamp: 'jmv 5/19/2009 10:24'!
printSpaceAnalysis: threshold on: aStream
	"SpaceTally new printSpaceAnalysis: 1 on:(FileStream forceNewFileNamed: 'STspace.text')"

	"sd-This method should be rewrote to be more coherent within the rest of the class 
	ie using preAllocate and spaceForInstanceOf:"

	"If threshold > 0, then only those classes with more than that number
	of instances will be shown, and they will be sorted by total instance space.
	If threshold = 0, then all classes will appear, sorted by name."

	| codeSpace instCount instSpace totalCodeSpace totalInstCount totalInstSpace eltSize n totalPercent percent |
	Smalltalk garbageCollect.
	totalCodeSpace _ totalInstCount _ totalInstSpace _ n _ 0.
	results _ OrderedCollection new: Smalltalk classNames size.
'Taking statistics...'
	displayProgressAt: Sensor cursorPoint
	from: 0 to: Smalltalk classNames size
	during: [:bar |
	Smalltalk allClassesDo:
		[:cl | codeSpace _ cl spaceUsed.
		bar value: (n _ n+1).
		Smalltalk garbageCollectMost.
		instCount _ cl instanceCount.
		instSpace _ (cl indexIfCompact > 0 ifTrue: [4] ifFalse: [8])*instCount. "Object headers"
		cl isVariable
			ifTrue: [eltSize _ cl isBytes ifTrue: [1] ifFalse: [4].
					cl allInstancesDo: [:x | instSpace _ instSpace + (x basicSize*eltSize)]]
			ifFalse: [instSpace _ instSpace + (cl instSize*instCount*4)].
		results add: (SpaceTallyItem analyzedClassName: cl name codeSize: codeSpace instanceCount:  instCount spaceForInstances: instSpace).
		totalCodeSpace _ totalCodeSpace + codeSpace.
		totalInstCount _ totalInstCount + instCount.
		totalInstSpace _ totalInstSpace + instSpace]].
	totalPercent _ 0.0.

	aStream timeStamp.
	aStream
		nextPutAll: ('Class' padded: #right to: 30 with: $ );
		nextPutAll: ('code space' padded: #left to: 12 with: $ );
		nextPutAll: ('# instances' padded: #left to: 12 with: $ );
		nextPutAll: ('inst space' padded: #left to: 12 with: $ );
		nextPutAll: ('percent' padded: #left to: 8 with: $ ); cr.

	threshold > 0 ifTrue: [
		"If inst count threshold > 0, then sort by space"
		results _ (results select: [:s | s instanceCount >= threshold or: [s spaceForInstances > (totalInstSpace // 500)]])
			asSortedCollection: [:s :s2 | s spaceForInstances > s2 spaceForInstances]].

	results do: [:s |
		aStream
			nextPutAll: (s analyzedClassName padded: #right to: 30 with: $ );
			nextPutAll: (s codeSize printString padded: #left to: 12 with: $ );
			nextPutAll: (s instanceCount printString padded: #left to: 12 with: $ );
			nextPutAll: (s spaceForInstances printString padded: #left to: 14 with: $ ).
		percent _ s spaceForInstances*100.0/totalInstSpace roundTo: 0.1.
		totalPercent _ totalPercent + percent.
		percent >= 0.1 ifTrue: [
			aStream nextPutAll: (percent printString padded: #left to: 8 with: $ )].
		aStream cr].

	aStream
		cr; nextPutAll: ('Total' padded: #right to: 30 with: $ );
		nextPutAll: (totalCodeSpace printString padded: #left to: 12 with: $ );
		nextPutAll: (totalInstCount printString padded: #left to: 12 with: $ );
		nextPutAll: (totalInstSpace printString padded: #left to: 14 with: $ );
		nextPutAll: ((totalPercent roundTo: 0.1) printString padded: #left to: 8 with: $ ).! !


!Utilities class methodsFor: 'vm statistics' stamp: 'jmv 5/19/2009 10:28'!
reportCPUandRAM
	"Write several text files with useful analysis for profiling purposes.
	Overwrites any existing report.
	Utilities reportCPUandRAM
	"	

	| stream tally |
	
	"VM statistics (Memory use and GC, mainly)"
	stream _ FileStream forceNewFileNamed: 'MemoryStats.txt'.
	[ stream nextPutAll: Utilities vmStatisticsReportString ] 
		ensure: [ stream close ].
	
	"Process taking most CPU"
	stream _ FileStream forceNewFileNamed: 'ThePig.txt'.
	ProcessBrowser dumpPigStackOn: stream andClose: true.
	
	"Tally of all processes"
	stream _ FileStream forceNewFileNamed: 'FullTally.txt'.
	[
		tally _ MessageTally new.
		tally spyEvery: 1 on: [ (Delay forMilliseconds: 1000) wait ].
		tally report: stream ] ensure: [ stream close ].
	
	"Tally of UI (perhaps not useful when having all processes....)"
	stream _ FileStream forceNewFileNamed: 'UITally.txt'.
	[
		tally _ MessageTally new.
		tally spyEvery: 1 on: [50 timesRepeat: [World doOneCycle]].
		tally report: stream ] ensure: [ stream close ].
	

	"Memory Analysis"
	stream _ FileStream forceNewFileNamed: 'MemoryAnalysis.txt'.
	[ SpaceTally new printSpaceAnalysis: 1 on: stream ]
		ensure: [ stream close ].! !

