mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
better benchmarking statistics
This commit is contained in:
parent
86b17e8972
commit
eac9c4d86b
|
@ -6,8 +6,8 @@ import (
|
||||||
"code.google.com/p/weed-fs/go/operation"
|
"code.google.com/p/weed-fs/go/operation"
|
||||||
"code.google.com/p/weed-fs/go/util"
|
"code.google.com/p/weed-fs/go/util"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/patrick-higgins/summstat"
|
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -68,13 +68,9 @@ var cmdBenchmark = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
countWritten int64
|
wait sync.WaitGroup
|
||||||
sizeWritten int64
|
writeStats *stats
|
||||||
countRead int64
|
readStats *stats
|
||||||
sizeRead int64
|
|
||||||
wait sync.WaitGroup
|
|
||||||
writeStats stats
|
|
||||||
readStats stats
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func runbenchmark(cmd *Command, args []string) bool {
|
func runbenchmark(cmd *Command, args []string) bool {
|
||||||
|
@ -88,39 +84,40 @@ func runbenchmark(cmd *Command, args []string) bool {
|
||||||
wait.Add(*b.concurrency)
|
wait.Add(*b.concurrency)
|
||||||
go writeFileIds(*b.idListFile, fileIdLineChan, finishChan)
|
go writeFileIds(*b.idListFile, fileIdLineChan, finishChan)
|
||||||
for i := 0; i < *b.concurrency; i++ {
|
for i := 0; i < *b.concurrency; i++ {
|
||||||
go writeFiles(idChan, fileIdLineChan)
|
go writeFiles(idChan, fileIdLineChan, writeStats)
|
||||||
}
|
}
|
||||||
|
writeStats.start = time.Now()
|
||||||
for i := 0; i < *b.numberOfFiles; i++ {
|
for i := 0; i < *b.numberOfFiles; i++ {
|
||||||
idChan <- i
|
idChan <- i
|
||||||
}
|
}
|
||||||
close(idChan)
|
close(idChan)
|
||||||
wait.Wait()
|
wait.Wait()
|
||||||
|
writeStats.end = time.Now()
|
||||||
wait.Add(1)
|
wait.Add(1)
|
||||||
finishChan <- true
|
finishChan <- true
|
||||||
wait.Wait()
|
wait.Wait()
|
||||||
println("completed", countWritten, "write requests, bytes:", sizeWritten)
|
writeStats.printStats("Writing Benchmark")
|
||||||
writeStats.printStats()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if *b.read {
|
if *b.read {
|
||||||
readStats = newStats()
|
readStats = newStats()
|
||||||
wait.Add(*b.concurrency)
|
wait.Add(*b.concurrency)
|
||||||
go readFileIds(*b.idListFile, fileIdLineChan)
|
go readFileIds(*b.idListFile, fileIdLineChan)
|
||||||
|
readStats.start = time.Now()
|
||||||
for i := 0; i < *b.concurrency; i++ {
|
for i := 0; i < *b.concurrency; i++ {
|
||||||
go readFiles(fileIdLineChan)
|
go readFiles(fileIdLineChan, readStats)
|
||||||
}
|
}
|
||||||
wait.Wait()
|
wait.Wait()
|
||||||
println("completed", countRead, "read requests, bytes:", sizeRead)
|
readStats.end = time.Now()
|
||||||
readStats.printStats()
|
readStats.printStats("Randomly Reading Benchmark")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFiles(idChan chan int, fileIdLineChan chan string) {
|
func writeFiles(idChan chan int, fileIdLineChan chan string, s *stats) {
|
||||||
for {
|
for {
|
||||||
if id, ok := <-idChan; ok {
|
if id, ok := <-idChan; ok {
|
||||||
countWritten++
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
fp := &operation.FilePart{Reader: &FakeReader{id: uint64(id), size: int64(*b.fileSize)}, FileSize: int64(*b.fileSize)}
|
fp := &operation.FilePart{Reader: &FakeReader{id: uint64(id), size: int64(*b.fileSize)}, FileSize: int64(*b.fileSize)}
|
||||||
if assignResult, err := operation.Assign(*b.server, 1, ""); err == nil {
|
if assignResult, err := operation.Assign(*b.server, 1, ""); err == nil {
|
||||||
|
@ -128,11 +125,13 @@ func writeFiles(idChan chan int, fileIdLineChan chan string) {
|
||||||
fp.Upload(0, *b.server, "")
|
fp.Upload(0, *b.server, "")
|
||||||
writeStats.addSample(time.Now().Sub(start))
|
writeStats.addSample(time.Now().Sub(start))
|
||||||
fileIdLineChan <- fp.Fid
|
fileIdLineChan <- fp.Fid
|
||||||
sizeWritten += int64(*b.fileSize)
|
s.transferred += int64(*b.fileSize)
|
||||||
|
s.completed++
|
||||||
if *cmdBenchmark.IsDebug {
|
if *cmdBenchmark.IsDebug {
|
||||||
fmt.Printf("writing %d file %s\n", id, fp.Fid)
|
fmt.Printf("writing %d file %s\n", id, fp.Fid)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
s.failed++
|
||||||
println("writing file error:", err.Error())
|
println("writing file error:", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +141,7 @@ func writeFiles(idChan chan int, fileIdLineChan chan string) {
|
||||||
wait.Done()
|
wait.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFiles(fileIdLineChan chan string) {
|
func readFiles(fileIdLineChan chan string, s *stats) {
|
||||||
for {
|
for {
|
||||||
if fid, ok := <-fileIdLineChan; ok {
|
if fid, ok := <-fileIdLineChan; ok {
|
||||||
if len(fid) == 0 {
|
if len(fid) == 0 {
|
||||||
|
@ -168,13 +167,15 @@ func readFiles(fileIdLineChan chan string) {
|
||||||
if server, ok := b.vid2server[vid]; ok {
|
if server, ok := b.vid2server[vid]; ok {
|
||||||
url := "http://" + server + "/" + fid
|
url := "http://" + server + "/" + fid
|
||||||
if bytesRead, err := util.Get(url); err == nil {
|
if bytesRead, err := util.Get(url); err == nil {
|
||||||
countRead++
|
s.completed++
|
||||||
sizeRead += int64(len(bytesRead))
|
s.transferred += int64(len(bytesRead))
|
||||||
readStats.addSample(time.Now().Sub(start))
|
readStats.addSample(time.Now().Sub(start))
|
||||||
} else {
|
} else {
|
||||||
|
s.failed++
|
||||||
println("!!!! Failed to read from ", url, " !!!!!")
|
println("!!!! Failed to read from ", url, " !!!!!")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
s.failed++
|
||||||
println("!!!! volume id ", vid, " location not found!!!!!")
|
println("!!!! volume id ", vid, " location not found!!!!!")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -221,31 +222,83 @@ func readFileIds(fileName string, fileIdLineChan chan string) {
|
||||||
close(fileIdLineChan)
|
close(fileIdLineChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
benchResolution = 10000 //0.1 microsecond
|
||||||
|
benchBucket = 1000000000 / benchResolution
|
||||||
|
)
|
||||||
|
|
||||||
type stats struct {
|
type stats struct {
|
||||||
stats *summstat.Stats
|
data []int
|
||||||
|
completed int
|
||||||
|
failed int
|
||||||
|
transferred int64
|
||||||
|
start time.Time
|
||||||
|
end time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStats() stats {
|
var percentages = []int{50, 66, 75, 80, 90, 95, 98, 99, 100}
|
||||||
s := stats{stats: summstat.NewStats()}
|
|
||||||
s.stats.CreateBins(21, 1000, 20000)
|
func newStats() *stats {
|
||||||
return s
|
return &stats{data: make([]int, benchResolution)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s stats) addSample(d time.Duration) {
|
func (s stats) addSample(d time.Duration) {
|
||||||
//fmt.Printf("adding %d μs\n", int(d / 1000))
|
s.data[int(d/benchBucket)]++
|
||||||
s.stats.AddSample(summstat.Sample(int(d / 1000)))
|
|
||||||
}
|
}
|
||||||
func (s stats) printStats() {
|
|
||||||
fmt.Printf("\n%s Count:%d ", time.Now().Local(), s.stats.Count())
|
func (s stats) printStats(testName string) {
|
||||||
fmt.Printf("Min:%.2fms ", s.stats.Min()/1000)
|
fmt.Printf("\n------------ %s ----------\n", testName)
|
||||||
fmt.Printf("Max:%.2fms ", s.stats.Max()/1000)
|
timeTaken := float64(int64(s.end.Sub(s.start))) / 1000000000
|
||||||
fmt.Printf("Stddev:%.2fms\n", s.stats.Stddev()/1000)
|
fmt.Printf("Concurrency Level: %d\n", *b.concurrency)
|
||||||
for b := 0; b < s.stats.NBins(); b++ {
|
fmt.Printf("Time taken for tests: %.3f seconds\n", timeTaken)
|
||||||
count, _, _ := s.stats.Bin(b)
|
fmt.Printf("Complete requests: %d\n", s.completed)
|
||||||
if b+1 != s.stats.NBins() {
|
fmt.Printf("Failed requests: %d\n", s.failed)
|
||||||
fmt.Printf("%2d ~ %2d ms: %2.4f%% %d\n", b, (b + 1), float64(count)*100.0/float64(s.stats.Count()), count)
|
fmt.Printf("Total transferred: %d bytes\n", s.transferred)
|
||||||
} else {
|
fmt.Printf("Requests per second: %.2f [#/sec]\n", float64(s.completed)/timeTaken)
|
||||||
fmt.Printf("%2d ~ ms: %2.4f%% %d\n", b, float64(count)*100.0/float64(s.stats.Count()), count)
|
fmt.Printf("Transfer rate: %.2f [Kbytes/sec]\n", float64(s.transferred)/1024/timeTaken)
|
||||||
|
n, sum := 0, 0
|
||||||
|
min, max := 10000000, 0
|
||||||
|
for i := 0; i < len(s.data); i++ {
|
||||||
|
n += s.data[i]
|
||||||
|
sum += s.data[i] * i
|
||||||
|
if s.data[i] > 0 {
|
||||||
|
if min > i {
|
||||||
|
min = i
|
||||||
|
}
|
||||||
|
if max < i {
|
||||||
|
max = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avg := float64(sum) / float64(n)
|
||||||
|
varianceSum := 0.0
|
||||||
|
for i := 0; i < len(s.data); i++ {
|
||||||
|
if s.data[i] > 0 {
|
||||||
|
d := float64(i) - avg
|
||||||
|
varianceSum += d * d * float64(s.data[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std := math.Sqrt(varianceSum / float64(n))
|
||||||
|
fmt.Printf("\nConnection Times (ms)\n")
|
||||||
|
fmt.Printf(" min avg max std\n")
|
||||||
|
fmt.Printf("Total: %2.1f %3.1f %3.1f %3.1f\n", float32(min)/10, float32(avg)/10, float32(max)/10, std/10)
|
||||||
|
//printing percentiles
|
||||||
|
fmt.Printf("\nPercentage of the requests served within a certain time (ms)\n")
|
||||||
|
percentiles := make([]int, len(percentages))
|
||||||
|
for i := 0; i < len(percentages); i++ {
|
||||||
|
percentiles[i] = n * percentages[i] / 100
|
||||||
|
}
|
||||||
|
percentiles[len(percentiles)-1] = n
|
||||||
|
percentileIndex := 0
|
||||||
|
currentSum := 0
|
||||||
|
for i := 0; i < len(s.data); i++ {
|
||||||
|
currentSum += s.data[i]
|
||||||
|
if s.data[i] > 0 && percentileIndex < len(percentiles) && currentSum >= percentiles[percentileIndex] {
|
||||||
|
fmt.Printf(" %3d%% %5.1f ms\n", percentages[percentileIndex], float32(i)/10.0)
|
||||||
|
percentileIndex++
|
||||||
|
for percentileIndex < len(percentiles) && currentSum >= percentiles[percentileIndex] {
|
||||||
|
percentileIndex++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue