buildbox- Rehackable components for writing buildbots and test harnesses.

Safe HaskellSafe-Infered




An aspect is a piece of data obtained from running a benchmark, like its total runtime, heap usage, or executable size. Aspects have physical units, so runtime is in seconds, and executable size is in bytes. The type system ensures that you can't mess up the units, such as by treating executable size as though it was measured in seconds.

Aspects are also parameterised over a carrier constructor, which is the collection type used to store the data. For single valued data use the Single constructor. For multi valued data use the [] (the list constructor). Use this when you have several readings for the same benchmark, like runtimes from multiple independent runs. Other useful constructors are Stats, Comparison and StatsComparison.

Once you have a many-valued aspect, you can use makeAspectStats to compute statistics from the data.

Here is a worked example:

 -- This is our original, single valued data.
someData :: [WithUnits (Aspect Single)]
someData =  [ Time TotalWall `secs`  100
            , Time TotalWall `secs`  85
            , Size ExeSize   `bytes` 1024
            , Used HeapMax   `bytes` 100000
            , Used HeapMax   `bytes` 100100]
 -- Collate the data, which groups all the readings for the same aspect into a list.
 -- Note that the carrier constructor is now [].
collated  :: [WithUnits (Aspect [])]
collated  = collateWithUnits someData
show collated 
  =>   [ WithSeconds (Time TotalWall [Seconds 100.0, Seconds 85.0])
       , WithBytes   (Used HeapMax   [Bytes 100000,  Bytes 100100])
       , WithBytes   (Size ExeSize   [Bytes 1024])]
 -- Extract statistics from the collated data.
analysed   :: [WithUnits (Aspect Stats)]
analysed   =  map (liftWithUnits makeAspectStats) collated
show analysed
  =>   [ WithSeconds (Time TotalWall (Stats {statsMin = Seconds 85.0, statsAvg = Seconds 92.5, statsMax = Seconds 100.0}))
       , WithBytes   (Used HeapMax   (Stats {statsMin = Bytes 100000, statsAvg = Bytes 100050, statsMax = Bytes 100100}))
       , WithBytes   (Size ExeSize   (Stats {statsMin = Bytes 1024,   statsAvg = Bytes 1024,   statsMax = Bytes 1024}))]




data Aspect c units whereSource

Holds a detail about a benchmark.

The c is the type constructor of the carrier that holds the data.

Useful instances for c include Single, `[ ]`, Stats, Comparison and StatsComparison.


Time :: Timed -> c Seconds -> Aspect c Seconds 
Size :: Sized -> c Bytes -> Aspect c Bytes 
Used :: Used -> c Bytes -> Aspect c Bytes 


Collatable Aspect 
(HasUnits (c units) units, Read (c units)) => Read (Aspect c units) 
Show (c units) => Show (Aspect c units) 
(Pretty (c Seconds), Pretty (c Bytes)) => Pretty (Aspect c units) 

makeAspect :: HasUnits (c units) units => Detail -> c units -> Maybe (Aspect c units)Source

Make an aspect from a named detail and data. If the detail doesn't match the units of the data then Nothing.

splitAspect :: Aspect c units -> (Detail, c units)Source

Split an aspect into its named detail and data.

Statistics and comparisons

makeAspectStats :: Aspect [] units -> Aspect Stats unitsSource

Compute statistics for many-valued aspects.

makeAspectComparison :: Real units => [Aspect Stats units] -> Aspect Stats units -> Aspect StatsComparison unitsSource

Lookup the baseline result for some aspect and produce a comparison.

makeAspectComparisons :: Real units => [Aspect Stats units] -> [Aspect Stats units] -> [Aspect StatsComparison units]Source

Compare lists of aspects. The first argument is the baseline.

Application functions

appAspect :: Real units => (c units -> b) -> Aspect c units -> bSource

Apply a function to the data in an aspect

appAspectWithUnits :: (forall units. Real units => c units -> b) -> WithUnits (Aspect c) -> bSource

Apply a function to the data in a wrapped aspect.

Lifting functions

liftAspect :: (c1 units -> c2 units) -> Aspect c1 units -> Aspect c2 unitsSource

Transform the data in an aspect, possibly changing the carrier type.

liftAspect2 :: (c1 units -> c1 units -> c2 units) -> Aspect c1 units -> Aspect c1 units -> Aspect c2 unitsSource

Apply a function to the aspect data, producing a new aspect. If the aspect details don't match then error.