98 lines
2.6 KiB
Go
98 lines
2.6 KiB
Go
|
/*
|
||
|
* MinIO Cloud Storage, (C) 2019 MinIO, 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 disk
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"math"
|
||
|
"time"
|
||
|
|
||
|
humanize "github.com/dustin/go-humanize"
|
||
|
)
|
||
|
|
||
|
var speedTestBlockSize = 4 * humanize.MiByte
|
||
|
|
||
|
// speedTestWrite computes the write speed by writing
|
||
|
// `speedTestFileSize` bytes of data to `w` in 4MiB direct-aligned
|
||
|
// blocks present in `buf`
|
||
|
func speedTestWrite(w io.Writer, buf []byte, size int64) (float64, error) {
|
||
|
// Write speedTestFileSize of data and record write speed
|
||
|
startTime := time.Now()
|
||
|
remaining := size
|
||
|
for remaining > 0 {
|
||
|
var toWrite int
|
||
|
// there's more remaining to write than the buffer can hold
|
||
|
if int64(len(buf)) < remaining {
|
||
|
toWrite = len(buf)
|
||
|
} else { // buffer can hold all there is to write
|
||
|
toWrite = int(remaining)
|
||
|
}
|
||
|
|
||
|
written, err := w.Write(buf[:toWrite])
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
remaining = remaining - int64(written)
|
||
|
}
|
||
|
|
||
|
elapsedTime := time.Since(startTime).Seconds()
|
||
|
totalWriteMBs := float64(size) / humanize.MiByte
|
||
|
writeSpeed := totalWriteMBs / elapsedTime
|
||
|
|
||
|
return roundToTwoDecimals(writeSpeed), nil
|
||
|
}
|
||
|
|
||
|
// speedTestRead computes the read speed by reading
|
||
|
// `speedTestFileSize` bytes from the reader `r` using 4MiB size `buf`
|
||
|
func speedTestRead(r io.Reader, buf []byte, size int64) (float64, error) {
|
||
|
// Read speedTestFileSize and record read speed
|
||
|
startTime := time.Now()
|
||
|
remaining := size
|
||
|
for remaining > 0 {
|
||
|
// reads `speedTestBlockSize` on every read
|
||
|
n, err := io.ReadFull(r, buf)
|
||
|
if err == io.ErrUnexpectedEOF || err == nil {
|
||
|
remaining = remaining - int64(n)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Nothing more left to read from the Reader
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
}
|
||
|
// Error while reading from the underlying Reader
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if remaining > 0 {
|
||
|
return 0, io.ErrUnexpectedEOF
|
||
|
}
|
||
|
|
||
|
elapsedTime := time.Since(startTime).Seconds()
|
||
|
totalReadMBs := float64(size) / humanize.MiByte
|
||
|
readSpeed := totalReadMBs / elapsedTime
|
||
|
|
||
|
return roundToTwoDecimals(readSpeed), nil
|
||
|
}
|
||
|
|
||
|
func roundToTwoDecimals(num float64) float64 {
|
||
|
return math.Round(num*100) / 100
|
||
|
}
|