mirror of https://github.com/etcd-io/dbtester.git
216 lines
6.7 KiB
Go
216 lines
6.7 KiB
Go
// Copyright 2017 CoreOS, Inc.
|
|
//
|
|
// 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 dbtester
|
|
|
|
import (
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/coreos/etcd/pkg/report"
|
|
)
|
|
|
|
// CumulativeKeyNumToAvgLatency wraps the cumulative number of keys
|
|
// and according latency data. So the higher 'CumulativeKeyNum' is,
|
|
// the later the data points are in the time series.
|
|
type CumulativeKeyNumToAvgLatency struct {
|
|
CumulativeKeyNum int64
|
|
|
|
MinLatency time.Duration
|
|
AvgLatency time.Duration
|
|
MaxLatency time.Duration
|
|
}
|
|
|
|
// CumulativeKeyNumToAvgLatencySlice is a slice of CumulativeKeyNumToAvgLatency to sort by CumulativeKeyNum.
|
|
type CumulativeKeyNumToAvgLatencySlice []CumulativeKeyNumToAvgLatency
|
|
|
|
func (t CumulativeKeyNumToAvgLatencySlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
|
func (t CumulativeKeyNumToAvgLatencySlice) Len() int { return len(t) }
|
|
func (t CumulativeKeyNumToAvgLatencySlice) Less(i, j int) bool {
|
|
return t[i].CumulativeKeyNum < t[j].CumulativeKeyNum
|
|
}
|
|
|
|
// FindRangesLatency sorts all data points by its timestamp.
|
|
// And then aggregate by the cumulative throughput,
|
|
// in order to map the number of keys to the average latency.
|
|
//
|
|
// type DataPoint struct {
|
|
// Timestamp int64
|
|
// MinLatency time.Duration
|
|
// AvgLatency time.Duration
|
|
// MaxLatency time.Duration
|
|
// ThroughPut int64
|
|
// }
|
|
//
|
|
// If unit is 1000 and the average throughput per second is 30,000
|
|
// and its average latency is 10ms, it will have 30 data points with
|
|
// latency 10ms.
|
|
func FindRangesLatency(data report.TimeSeries, unit int64, totalRequests int64) CumulativeKeyNumToAvgLatencySlice {
|
|
// need to sort by timestamps because we want the 'cumulative'
|
|
// trends as we write more keys, 'report.TimeSeries' already implements
|
|
// sort interface, so just sort.Sort(data)
|
|
sort.Sort(data)
|
|
|
|
cumulKeyN := int64(0)
|
|
maxKey := int64(0)
|
|
|
|
rm := make(map[int64]CumulativeKeyNumToAvgLatency)
|
|
|
|
// this data is aggregated by second
|
|
// and we want to map number of keys to latency
|
|
// so the range is the key
|
|
// and the value is the cumulative throughput
|
|
for _, ts := range data {
|
|
cumulKeyN += ts.ThroughPut
|
|
if cumulKeyN < unit {
|
|
// not enough data points yet
|
|
continue
|
|
}
|
|
|
|
// cumulKeyN >= unit
|
|
for cumulKeyN > maxKey {
|
|
maxKey += unit
|
|
rm[maxKey] = CumulativeKeyNumToAvgLatency{
|
|
MinLatency: ts.MinLatency,
|
|
AvgLatency: ts.AvgLatency,
|
|
MaxLatency: ts.MaxLatency,
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill-in empty rows
|
|
for i := maxKey; i < totalRequests; i += unit {
|
|
if _, ok := rm[i]; !ok {
|
|
rm[i] = CumulativeKeyNumToAvgLatency{}
|
|
}
|
|
}
|
|
if _, ok := rm[totalRequests]; !ok {
|
|
rm[totalRequests] = CumulativeKeyNumToAvgLatency{}
|
|
}
|
|
|
|
kss := []CumulativeKeyNumToAvgLatency{}
|
|
delete(rm, 0) // drop data at beginning
|
|
|
|
for k, v := range rm {
|
|
// make sure to use 'k' as CumulativeKeyNum
|
|
kss = append(kss, CumulativeKeyNumToAvgLatency{
|
|
CumulativeKeyNum: k,
|
|
MinLatency: v.MinLatency,
|
|
AvgLatency: v.AvgLatency,
|
|
MaxLatency: v.MaxLatency,
|
|
})
|
|
}
|
|
|
|
// sort by cumulative throughput (number of keys) in ascending order
|
|
sort.Sort(CumulativeKeyNumToAvgLatencySlice(kss))
|
|
return kss
|
|
}
|
|
|
|
// CumulativeKeyNumAndOtherData wraps the cumulative number of keys
|
|
// and according memory data. So the higher 'CumulativeKeyNum' is,
|
|
// the later the data points are in the time series.
|
|
type CumulativeKeyNumAndOtherData struct {
|
|
UnixSecond int64
|
|
Throughput int64
|
|
|
|
CumulativeKeyNum int64
|
|
|
|
MinMemoryMB float64
|
|
AvgMemoryMB float64
|
|
MaxMemoryMB float64
|
|
|
|
AvgReadBytesDelta float64
|
|
AvgWriteBytesDelta float64
|
|
}
|
|
|
|
// CumulativeKeyNumAndOtherDataSlice is a slice of CumulativeKeyNumAndOtherData to sort by CumulativeKeyNum.
|
|
type CumulativeKeyNumAndOtherDataSlice []CumulativeKeyNumAndOtherData
|
|
|
|
func (t CumulativeKeyNumAndOtherDataSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
|
func (t CumulativeKeyNumAndOtherDataSlice) Len() int { return len(t) }
|
|
func (t CumulativeKeyNumAndOtherDataSlice) Less(i, j int) bool {
|
|
return t[i].CumulativeKeyNum < t[j].CumulativeKeyNum
|
|
}
|
|
|
|
// CumulativeKeyNumAndOtherDataByUnixSecond is a slice of CumulativeKeyNumAndOtherData to sort by UnixSecond.
|
|
type CumulativeKeyNumAndOtherDataByUnixSecond []CumulativeKeyNumAndOtherData
|
|
|
|
func (t CumulativeKeyNumAndOtherDataByUnixSecond) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
|
func (t CumulativeKeyNumAndOtherDataByUnixSecond) Len() int { return len(t) }
|
|
func (t CumulativeKeyNumAndOtherDataByUnixSecond) Less(i, j int) bool {
|
|
return t[i].UnixSecond < t[j].UnixSecond
|
|
}
|
|
|
|
// FindRangesData sorts all data points by its timestamp.
|
|
// And then aggregate by the cumulative throughput,
|
|
// in order to map the number of keys to the average memory usage.
|
|
func FindRangesData(data []CumulativeKeyNumAndOtherData, unit int64, totalRequests int64) CumulativeKeyNumAndOtherDataSlice {
|
|
// need to sort by timestamps because we want the 'cumulative'
|
|
// trends as we write more keys, 'report.TimeSeries' already implements
|
|
// sort interface, so just sort.Sort(data)
|
|
sort.Sort(CumulativeKeyNumAndOtherDataByUnixSecond(data))
|
|
|
|
cumulKeyN := int64(0)
|
|
maxKey := int64(0)
|
|
|
|
rm := make(map[int64]CumulativeKeyNumAndOtherData)
|
|
|
|
// this data is aggregated by second
|
|
// and we want to map number of keys to memory usage
|
|
// so the range is the key
|
|
// and the value is the cumulative throughput
|
|
for _, ts := range data {
|
|
cumulKeyN += ts.Throughput
|
|
if cumulKeyN < unit {
|
|
// not enough data points yet
|
|
continue
|
|
}
|
|
|
|
// cumulKeyN >= unit
|
|
for cumulKeyN > maxKey {
|
|
maxKey += unit
|
|
rm[maxKey] = ts
|
|
}
|
|
}
|
|
|
|
// fill-in empty rows
|
|
for i := maxKey; i < int64(totalRequests); i += unit {
|
|
if _, ok := rm[i]; !ok {
|
|
rm[i] = CumulativeKeyNumAndOtherData{}
|
|
}
|
|
}
|
|
if _, ok := rm[int64(totalRequests)]; !ok {
|
|
rm[int64(totalRequests)] = CumulativeKeyNumAndOtherData{}
|
|
}
|
|
|
|
kss := []CumulativeKeyNumAndOtherData{}
|
|
delete(rm, 0) // drop data at beginning
|
|
|
|
for k, v := range rm {
|
|
// make sure to use 'k' as keyNum
|
|
kss = append(kss, CumulativeKeyNumAndOtherData{
|
|
CumulativeKeyNum: k,
|
|
MinMemoryMB: v.MinMemoryMB,
|
|
AvgMemoryMB: v.AvgMemoryMB,
|
|
MaxMemoryMB: v.MaxMemoryMB,
|
|
AvgReadBytesDelta: v.AvgReadBytesDelta,
|
|
AvgWriteBytesDelta: v.AvgWriteBytesDelta,
|
|
})
|
|
}
|
|
|
|
// sort by cumulative throughput (number of keys) in ascending order
|
|
sort.Sort(CumulativeKeyNumAndOtherDataSlice(kss))
|
|
return kss
|
|
}
|