s/BenchmarkInstance.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Wed, 05 Jun 2013 10:45:29 +0100
changeset 6 25b264cec44e
parent 5 8669edf62d9b
child 11 88ec277d733a
permissions -rw-r--r--
Added parameter to BenchmarkResult to run each benchmark multiple times. The BenchmarkOutcome keeps all times. Also, BenchmarkInstance>>benchmark renamed to selector.

"{ Package: 'jv:calipel/s' }"

Object subclass:#BenchmarkInstance
	instanceVariableNames:'instance benchmarkSelector setUpSelector1 setUpSelector2
		tearDownSelector1 tearDownSelector2 warmUpSelector1
		warmUpSelector2'
	classVariableNames:'MillisecondsTime'
	poolDictionaries:''
	category:'CalipeL/S-Core'
!


!BenchmarkInstance class methodsFor:'instance creation'!

class:class selector:benchmark 
    ^ self new class:class selector:benchmark

    "Created: / 27-05-2013 / 19:04:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!BenchmarkInstance class methodsFor:'class initialization'!

initialize 
   "Test for Smalltalk/X"
    ((Smalltalk respondsTo: #isSmalltalkX) and:[ Smalltalk isSmalltalkX ]) ifTrue:[
          "Use slow Smalltalk at: because Pharo does not allow to accept code with
            undefined global. Somewhat stupid!! "
        MillisecondsTime := [ (Smalltalk at: #OperatingSystem) getMillisecondTime ].
          ^self
    ].
   "Test for Squeak/Pharo"
   (Smalltalk at: #SmalltalkImage ifAbsent: [nil]) notNil ifTrue:[
        MillisecondsTime := [ Time millisecondClockValue ].
          ^self 
   ].
   self error:'Unssuported platform'

   "
   BenchmarkInstance initialize
   "

    "Created: / 31-05-2013 / 12:02:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!BenchmarkInstance methodsFor:'accessing'!

instance
    ^ instance
!

selector
    ^ benchmarkSelector
! !

!BenchmarkInstance methodsFor:'initialization'!

class:class selector:benchmark 
    self instance:class new selector:benchmark

    "Created: / 27-05-2013 / 19:04:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

instance:anObject selector:aSelector 
    | benchmarkMethod  annotation |

    (anObject respondsTo:aSelector) ifFalse:[
        self 
            error:'Object does not respond to benchmark (no ' 
                    , anObject class printString , '>>' 
                    , aSelector storeString.
    ].
    instance := anObject.
    benchmarkSelector := aSelector.
    instance class methodDictionary 
        keysAndValuesDo:[:selector :method | 
            method numArgs == 0 ifTrue:[
                (method pragmaAt:#setup) notNil ifTrue:[
                    setUpSelector1 notNil ifTrue:[
                        self error:'More than one <setup> method'.
                    ].
                    setUpSelector1 := selector.
                ].
                (method pragmaAt:#teardown) notNil ifTrue:[
                    tearDownSelector1 notNil ifTrue:[
                        self error:'More than one <teardown> method'.
                    ].
                    tearDownSelector1 := selector.
                ].
                (method pragmaAt:#warmup) notNil ifTrue:[
                    warmUpSelector1 notNil ifTrue:[
                        self error:'More than one <warmup> method'.
                    ].
                    warmUpSelector1 := selector.
                ].
            ].
        ].
    benchmarkMethod := instance class compiledMethodAt:benchmarkSelector.
    annotation := benchmarkMethod pragmaAt:#setup:.
    annotation notNil ifTrue:[
        | method  selector |

        selector := annotation argumentAt:1.
        selector isSymbol ifFalse:[
            self error:'<setup:> annotation argument not a symbol'.
        ].
        method := instance compiledMethodAt:selector ifAbsent:[ nil ].
        method isNil ifTrue:[
            self error:'<setup:> method does not exist (' , selector , ')'.
        ].
        method numArgs ~~ 0 ifTrue:[
            self error:'<setup:> method has arguments (' , selector , ')'.
        ].
        setUpSelector2 := selector.
    ].
    annotation := benchmarkMethod pragmaAt:#teardown:.
    annotation notNil ifTrue:[
        | method  selector |

        selector := annotation argumentAt:1.
        selector isSymbol ifFalse:[
            self error:'<teardown:> annotation argument not a symbol'.
        ].
        method := instance compiledMethodAt:selector ifAbsent:[ nil ].
        method isNil ifTrue:[
            self error:'<teardown:> method does not exist (' , selector , ')'.
        ].
        method numArgs ~~ 0 ifTrue:[
            self error:'<teardown:> method has arguments (' , selector , ')'.
        ].
        tearDownSelector2 := selector.
    ].
    annotation := benchmarkMethod pragmaAt:#warmup:.
    annotation notNil ifTrue:[
        | method  selector |

        selector := annotation argumentAt:1.
        selector isSymbol ifFalse:[
            self error:'<warmup:> annotation argument not a symbol'.
        ].
        method := instance compiledMethodAt:selector ifAbsent:[ nil ].
        method isNil ifTrue:[
            self error:'<warmup:> method does not exist (' , selector , ')'.
        ].
        method numArgs ~~ 0 ifTrue:[
            self error:'<warmup:> method has arguments (' , selector , ')'.
        ].
        warmUpSelector2 := selector.
    ].

    "Created: / 27-05-2013 / 19:06:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 10:57:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!BenchmarkInstance methodsFor:'running'!

run
    ^self run: BenchmarkResult new.

    "Created: / 27-05-2013 / 19:10:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

run: aBenchmarkResult
    ^self run: aBenchmarkResult with: Dictionary new

    "Created: / 27-05-2013 / 19:10:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 00:02:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

run: aBenchmarkResult with: aDictionary
    aBenchmarkResult runBenchmark: self withParameters: aDictionary.
    ^aBenchmarkResult

    "Created: / 27-05-2013 / 22:18:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

runBenchmarkWithParameters:aBenchmarkParameterSet 
    | t |

    t := -1.
    [
        self setUp.
        self setUpParameters:aBenchmarkParameterSet.
        self warmUp.
        t := self benchmark.
    ] ensure:[ self tearDown. ].
    ^ t

    "Created: / 27-05-2013 / 22:25:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 08:49:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

runWith: aDictionary
    ^self run: BenchmarkResult new with: aDictionary

    "Created: / 27-05-2013 / 22:18:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!BenchmarkInstance methodsFor:'running-private'!

benchmark
    | t0  t1 |

    t0 := MillisecondsTime value.
    instance perform:benchmarkSelector.
    t1 := MillisecondsTime value.
    ^ t1 - t0

    "Created: / 28-05-2013 / 08:49:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 31-05-2013 / 12:02:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setUp
    setUpSelector1 notNil ifTrue:[
        instance perform: setUpSelector1 
    ].
    setUpSelector2 notNil ifTrue:[
        instance perform: setUpSelector2 
    ].

    "Created: / 27-05-2013 / 19:02:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 10:58:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setUpParameter: name from: parameters type: type values: values
    | key1 key2  valueString value |

    key1 := instance class name , '#' , name.
    key2 := name.
    valueString := parameters at: key1 ifAbsent:[parameters at: key2 ifAbsent:[^ self]].
    (type includesBehavior: CharacterArray) ifTrue:[
        value := valueString.
    ] ifFalse:[
        value := type readFrom: valueString onError:[ self error:'Cannot read parameter '. name ,' (conversion error)'].
    ].
    values notNil ifTrue:[
        (values includes: value) ifFalse:[
            self error: 'Invalid parameter value for ', name , ' (' , value storeString ,')'
        ].
    ].
    instance perform: (name , ':') asSymbol with: value.

    "Created: / 28-05-2013 / 00:01:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setUpParameters: aDictionary
    instance class methodDictionary keysAndValuesDo:[:selector :method |
        | annotation name type values value |
        method numArgs == 1 ifTrue:[
            (annotation := method pragmaAt: #parameter:) notNil ifTrue:[
                type := Smalltalk at: (annotation argumentAt: 1)
            ] ifFalse:[
                (annotation := method pragmaAt: #parameter:values:) notNil ifTrue:[
                    type :=  Smalltalk at: (annotation argumentAt: 1).
                    values := (annotation argumentAt: 2)
                ]
            ].
            annotation notNil ifTrue:[
                name := selector.
                name last = $: ifTrue:[
                    name := name copyWithoutLast: 1.
                ].
                self setUpParameter: name from: aDictionary type: type values: values  
            ].
        ].
    ]

    "Created: / 27-05-2013 / 22:27:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 00:08:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

tearDown
    tearDownSelector1 notNil ifTrue:[
        instance perform: tearDownSelector1 
    ].
    tearDownSelector2 notNil ifTrue:[
        instance perform: tearDownSelector2
    ].

    "Created: / 27-05-2013 / 19:02:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 28-05-2013 / 10:58:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

warmUp
    | warmed |

    warmed := false.
    warmUpSelector1 notNil ifTrue:[
        instance perform: warmUpSelector1.
        warmed := true.
    ].
    warmUpSelector2 notNil ifTrue:[
        instance perform: warmUpSelector2.
        warmed := true.
    ].
    "Default warmup"
    warmed ifFalse:[
        instance perform: benchmarkSelector 
    ].
    ObjectMemory garbageCollect; tenure.

    "Created: / 27-05-2013 / 19:02:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 04-06-2013 / 22:19:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!BenchmarkInstance class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
!

version_MC
    ^ 'CalipeL_S-Core-JanVrany.7 5c300a20-c9d7-11e2-a959-606720e43e2c 2013-05-31T10:49:17 JanVrany'
! !


BenchmarkInstance initialize!