blob: 1f947d7dceb66c514a0a2d84503da73c1f8de93b [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"time"
"android.googlesource.com/platform/tools/gpu/framework/benchmark"
)
// Sample is a time.Duration with more readable JSON serialization.
type Sample time.Duration
// Multisample represents a collection of AnnotatedSamples gathered through
// multiple runs of a
type Multisample []Sample
// KeyedSamples maps atom indices to Multisamples.
type KeyedSamples map[string]*Multisample
// IndexedMultisample is a Multisample together with an atom index.
type IndexedMultisample struct {
Index int64
Values *Multisample
}
// IndexedMultisamples is a slice of IndexedMultisample, sortable by
// index and usable for plotting or complexity analysis.
type IndexedMultisamples []IndexedMultisample
// Analyse analyses the samples and returns the algorithmic cost.
func (s IndexedMultisamples) Analyse(accessor func(*Multisample) time.Duration) benchmark.Fit {
samples := benchmark.Samples{}
for _, m := range s {
samples.Add(int(m.Index), accessor(m.Values))
}
return samples.Analyse()
}
// NewKeyedSamples instantiates a new KeyedSamples.
func NewKeyedSamples() KeyedSamples {
return make(map[string]*Multisample)
}
// Add records a new duration associated with the given index.
func (m KeyedSamples) Add(index int64, t time.Duration) {
key := fmt.Sprintf("%010d", index) // Easiest way to have samples show up in sorted order in the json.
ms, found := m[key]
if !found {
ms = new(Multisample)
m[key] = ms
}
ms.Add(t)
}
// IndexedMultisamples returns a sortable array of indexed multisamples.
func (m KeyedSamples) IndexedMultisamples() IndexedMultisamples {
result := make(IndexedMultisamples, len(m))
i := 0
for key, values := range m {
index, _ := strconv.ParseInt(key, 10, 64)
result[i] = IndexedMultisample{Index: index, Values: values}
i++
}
sort.Sort(result)
return result
}
func (s IndexedMultisamples) Len() int { return len(s) }
func (s IndexedMultisamples) Less(i, j int) bool {
return s[i].Index < s[j].Index
}
func (s IndexedMultisamples) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (a *Sample) Set(t time.Duration) {
*a = Sample(t)
}
func (a Sample) Duration() time.Duration {
return time.Duration(a)
}
func (a *Sample) UnmarshalJSON(b []byte) error {
var durationString string
if err := json.Unmarshal(b, &durationString); err != nil {
return err
}
duration, err := time.ParseDuration(durationString)
if err != nil {
return err
}
a.Set(duration)
return nil
}
func (a Sample) MarshalJSON() ([]byte, error) {
return json.Marshal(a.Duration().String())
}
func (s *Multisample) AddWithData(t time.Duration, data string) {
*s = append(*s, Sample(t))
}
func (s *Multisample) Len() int {
return len(*s)
}
func (s *Multisample) Clear() {
*s = make([]Sample, 0)
}
func (s *Multisample) Add(t time.Duration) {
*s = append(*s, Sample(t))
}
func (s *Multisample) Average() time.Duration {
sum := int64(0)
for _, value := range *s {
sum += int64(value.Duration())
}
return time.Duration(sum / int64(len(*s)))
}
func (s *Multisample) Min() time.Duration {
min := time.Duration(1<<63 - 1)
for _, value := range *s {
if value.Duration() < min {
min = value.Duration()
}
}
return min
}
func (s *Multisample) Max() time.Duration {
max := time.Duration(-1 << 63)
for _, value := range *s {
if value.Duration() > max {
max = value.Duration()
}
}
return max
}
func (s *Multisample) Median() time.Duration {
arr := make([]int64, len(*s))
for i := range arr {
arr[i] = int64((*s)[i].Duration())
}
sort.Sort(int64Slice(arr))
if len(arr)%2 != 0 {
return time.Duration(arr[len(arr)/2])
} else {
return time.Duration((arr[len(arr)/2-1] + arr[len(arr)/2]) / 2)
}
}
type int64Slice []int64
func (p int64Slice) Len() int { return len(p) }
func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }