Example #1
0
func readSequential(
	r io.ReadSeeker,
	readSize int,
	desiredDuration time.Duration) (err error) {
	buf := make([]byte, readSize)
	start := time.Now()

	var readCount int64
	var bytesRead int64
	for time.Since(start) < desiredDuration {
		var n int
		n, err = r.Read(buf)

		switch {
		case err == io.EOF:
			_, err = r.Seek(0, 0)
			if err != nil {
				err = fmt.Errorf("Seek: %v", err)
				return
			}

		case err != nil:
			err = fmt.Errorf("Read: %v", err)
		}

		bytesRead += int64(n)
		readCount++
	}

	d := time.Since(start)

	// Report.
	seconds := float64(d) / float64(time.Second)
	readsPerSec := float64(readCount) / seconds
	bytesPerSec := float64(bytesRead) / seconds

	fmt.Printf(
		"Read %d times (%s) in %v (%.1f Hz, %s/s)\n",
		readCount,
		format.Bytes(float64(bytesRead)),
		d,
		readsPerSec,
		format.Bytes(bytesPerSec))

	fmt.Println()
	return
}
Example #2
0
func readRandom(
	r io.ReaderAt,
	fileSize int64,
	readSize int,
	desiredDuration time.Duration) (err error) {
	// Make sure the logic below for choosing offsets works.
	if fileSize < int64(readSize) {
		err = fmt.Errorf(
			"File size of %d bytes not large enough for reads of %d bytes",
			fileSize,
			readSize)
		return
	}

	buf := make([]byte, readSize)

	start := time.Now()
	var readCount int64
	var bytesRead int64
	for time.Since(start) < desiredDuration {
		// Choose a random offset at which to read.
		off := rand.Int63n(fileSize - int64(readSize))

		// Read, ignoring io.EOF which io.ReaderAt is allowed to return for reads
		// that abut the end of the file.
		var n int
		n, err = r.ReadAt(buf, off)

		switch {
		case err == io.EOF && n == readSize:
			err = nil

		case err != nil:
			err = fmt.Errorf("ReadAt: %v", err)
			return
		}

		readCount++
		bytesRead += int64(n)
	}

	d := time.Since(start)

	// Report.
	seconds := float64(d) / float64(time.Second)
	readsPerSec := float64(readCount) / seconds

	fmt.Printf(
		"Read %d times (%s) in %v (%.1f Hz)\n",
		readCount,
		format.Bytes(float64(bytesRead)),
		d,
		readsPerSec)

	fmt.Println()

	return
}
Example #3
0
func run() (err error) {
	if *fFile == "" {
		err = errors.New("You must set --file.")
		return
	}

	// Open the file for reading.
	f, err := os.Open(*fFile)
	if err != nil {
		return
	}

	// Find its size.
	size, err := f.Seek(0, 2)
	if err != nil {
		err = fmt.Errorf("Seek: %v", err)
		return
	}

	log.Printf("%s has size %s.", f.Name(), format.Bytes(float64(size)))

	// Perform reads.
	if *fRandom {
		err = readRandom(f, size, *fReadSize, *fDuration)
		if err != nil {
			err = fmt.Errorf("readRandom: %v", err)
			return
		}
	} else {
		err = readSequential(f, *fReadSize, *fDuration)
		if err != nil {
			err = fmt.Errorf("readSequential: %v", err)
			return
		}
	}

	return
}
Example #4
0
func run() (err error) {
	if *fDir == "" {
		err = errors.New("You must set --dir.")
		return
	}

	// Create a temporary file.
	log.Printf("Creating a temporary file in %s.", *fDir)

	f, err := ioutil.TempFile(*fDir, "write_locally")
	if err != nil {
		err = fmt.Errorf("TempFile: %v", err)
		return
	}

	path := f.Name()

	// Make sure we clean it up later.
	defer func() {
		log.Printf("Truncating and closing %s.", path)
		f.Truncate(0)
		f.Close()

		log.Printf("Deleting %s.", path)
		os.Remove(path)
	}()

	// Extend to the initial size.
	log.Printf("Truncating to %d bytes.", *fFileSize)

	err = f.Truncate(*fFileSize)
	if err != nil {
		err = fmt.Errorf("Truncate: %v", err)
		return
	}

	// Repeatedly overwrite the file with zeroes.
	log.Println("Measuring...")

	var bytesWritten int64
	var writeCount int64

	buf := make([]byte, *fWriteSize)
	start := time.Now()

	for time.Since(start) < *fDuration {
		// Seek to the beginning.
		_, err = f.Seek(0, 0)
		if err != nil {
			err = fmt.Errorf("Seek: %v", err)
			return
		}

		// Overwrite.
		var n int64
		for n < *fFileSize && time.Since(start) < *fDuration {
			toWrite := *fFileSize - n
			if toWrite > *fWriteSize {
				toWrite = *fWriteSize
			}

			var tmp int
			tmp, err = f.Write(buf)
			if err != nil {
				err = fmt.Errorf("Write: %v", err)
				return
			}

			n += int64(tmp)
			bytesWritten += int64(tmp)
			writeCount++
		}
	}

	d := time.Since(start)

	// Report.
	seconds := float64(d) / float64(time.Second)
	writesPerSec := float64(writeCount) / seconds
	bytesPerSec := float64(bytesWritten) / seconds

	fmt.Printf(
		"Wrote %d times (%s) in %v (%.1f Hz, %s/s)\n",
		writeCount,
		format.Bytes(float64(bytesWritten)),
		d,
		writesPerSec,
		format.Bytes(bytesPerSec))

	fmt.Println()
	return
}
Example #5
0
func run() (err error) {
	if *fDir == "" {
		err = errors.New("You must set --dir.")
		return
	}

	// Create a temporary file.
	log.Printf("Creating a temporary file in %s.", *fDir)

	f, err := ioutil.TempFile(*fDir, "write_to_gcs")
	if err != nil {
		err = fmt.Errorf("TempFile: %v", err)
		return
	}

	path := f.Name()

	// Make sure we clean it up later.
	defer func() {
		log.Printf("Deleting %s.", path)
		os.Remove(path)
	}()

	// Write the configured number of zeroes to the file, measuing the time
	// taken.
	log.Println("Writing...")

	buf := make([]byte, *fWriteSize)

	var bytesWritten int64
	start := time.Now()

	for bytesWritten < *fFileSize {
		// Decide how many bytes to write.
		toWrite := *fFileSize - bytesWritten
		if toWrite > *fWriteSize {
			toWrite = *fWriteSize
		}

		// Write them.
		_, err = f.Write(buf)
		if err != nil {
			err = fmt.Errorf("Write: %v", err)
			return
		}

		bytesWritten += toWrite
	}

	writeDuration := time.Since(start)

	// Close the file, measuring the time taken.
	log.Println("Flushing...")

	start = time.Now()
	err = f.Close()
	closeDuration := time.Since(start)

	if err != nil {
		err = fmt.Errorf("Close: %v", err)
		return
	}

	// Report.
	{
		seconds := float64(writeDuration) / float64(time.Second)
		bytesPerSec := float64(bytesWritten) / seconds

		fmt.Printf(
			"Wrote %s in %v (%s/s)\n",
			format.Bytes(float64(bytesWritten)),
			writeDuration,
			format.Bytes(bytesPerSec))
	}

	{
		seconds := float64(closeDuration) / float64(time.Second)
		bytesPerSec := float64(bytesWritten) / seconds

		fmt.Printf(
			"Flushed %s in %v (%s/s)\n",
			format.Bytes(float64(bytesWritten)),
			closeDuration,
			format.Bytes(bytesPerSec))
	}

	fmt.Println()
	return
}
Example #6
0
func run() (err error) {
	if *fDir == "" {
		err = errors.New("You must set --dir.")
		return
	}

	// Create a temporary file.
	log.Printf("Creating a temporary file in %s.", *fDir)

	f, err := ioutil.TempFile(*fDir, "sequential_read")
	if err != nil {
		err = fmt.Errorf("TempFile: %v", err)
		return
	}

	path := f.Name()

	// Make sure we clean it up later.
	defer func() {
		log.Printf("Deleting %s.", path)
		os.Remove(path)
	}()

	// Fill it with random content.
	log.Printf("Writing %d random bytes.", *fFileSize)
	_, err = io.Copy(f, io.LimitReader(rand.Reader, *fFileSize))
	if err != nil {
		err = fmt.Errorf("Copying random bytes: %v", err)
		return
	}

	// Finish off the file.
	err = f.Close()
	if err != nil {
		err = fmt.Errorf("Closing file: %v", err)
		return
	}

	// Run several iterations.
	log.Printf("Measuring for %v...", *fDuration)

	var fullFileRead percentile.DurationSlice
	var singleReadCall percentile.DurationSlice
	buf := make([]byte, *fReadSize)

	overallStartTime := time.Now()
	for len(fullFileRead) == 0 || time.Since(overallStartTime) < *fDuration {
		// Open the file for reading.
		f, err = os.Open(path)
		if err != nil {
			err = fmt.Errorf("Opening file: %v", err)
			return
		}

		// Read the whole thing.
		fileStartTime := time.Now()
		for err == nil {
			readStartTime := time.Now()
			_, err = f.Read(buf)
			singleReadCall = append(singleReadCall, time.Since(readStartTime))
		}

		fullFileRead = append(fullFileRead, time.Since(fileStartTime))

		switch {
		case err == io.EOF:
			err = nil

		case err != nil:
			err = fmt.Errorf("Reading: %v", err)
			return
		}

		// Close the file.
		err = f.Close()
		if err != nil {
			err = fmt.Errorf("Closing file after reading: %v", err)
			return
		}
	}

	sort.Sort(fullFileRead)
	sort.Sort(singleReadCall)

	log.Printf(
		"Read the file %d times, using %d calls to read(2).",
		len(fullFileRead),
		len(singleReadCall))

	// Report.
	ptiles := []int{50, 90, 98}

	reportSlice := func(
		name string,
		bytesPerObservation int64,
		observations percentile.DurationSlice) {
		fmt.Printf("\n%s:\n", name)
		for _, ptile := range ptiles {
			d := percentile.Duration(observations, ptile)
			seconds := float64(d) / float64(time.Second)
			bandwidthBytesPerSec := float64(bytesPerObservation) / seconds

			fmt.Printf(
				"  %02dth ptile: %10v (%s/s)\n",
				ptile,
				d,
				format.Bytes(bandwidthBytesPerSec))
		}
	}

	reportSlice("Full-file read times", *fFileSize, fullFileRead)
	reportSlice("read(2) latencies", *fReadSize, singleReadCall)

	fmt.Println()

	return
}