func (bm *Mark) SetBonnieDir(parentDir string) error {
	err := createDirIfNeeded(parentDir)
	if err != nil {
		return err
	}
	bm.BonnieDir = path.Join(parentDir, "gobonniego")
	return createDirIfNeeded(bm.BonnieDir)
}
calling program should `defer os.RemoveAll(bm.BonnieDir)` to clean up after run
package bench
import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cunnie/gobonniego/mem"
	"io"
	"math/rand"
	"os"
	"path"
	"time"
)
const Version = "1.0.9"
const Blocksize = 0x1 << 16  
type Mark struct {
	Start                       time.Time `json:"start_time"`
	BonnieDir                   string    `json:"gobonniego_directory"`
	AggregateTestFilesSizeInGiB float64   `json:"disk_space_used_gib"`
	NumReadersWriters           int       `json:"num_readers_and_writers"`
	PhysicalMemory              uint64    `json:"physical_memory_bytes"`
	IODuration                  float64   `json:"iops_duration_seconds"`
	Results                     []Result  `json:"results"`
	fileSize                    int
	randomBlock                 []byte
}
type Result struct {
	Start           time.Time     `json:"start_time"`
	WrittenBytes    int           `json:"write_bytes"`
	WrittenDuration time.Duration `json:"write_seconds"`
	ReadBytes       int           `json:"read_bytes"`
	ReadDuration    time.Duration `json:"read_seconds"`
	IOOperations    int           `json:"io_operations"`
	IODuration      time.Duration `json:"io_seconds"`
}
type ThreadResult struct {
	Result int  
	Error  error
}
func (bm *Mark) Version() string {
	return Version
}
func (bm *Mark) RunSequentialWriteTest() error {
	bm.fileSize = (int(bm.AggregateTestFilesSizeInGiB*(1<<10)) << 20) / bm.NumReadersWriters
	for i := 0; i < bm.NumReadersWriters; i++ {
		err := os.RemoveAll(path.Join(bm.BonnieDir, fmt.Sprintf("bonnie.%d", i)))
		if err != nil {
			return err
		}
	}
	bm.Results = append(bm.Results, Result{Start: time.Now()})  
	newResult := &bm.Results[len(bm.Results)-1]
	bytesWritten := make(chan ThreadResult)
	start := time.Now()
	for i := 0; i < bm.NumReadersWriters; i++ {
		go bm.singleThreadWriteTest(path.Join(bm.BonnieDir, fmt.Sprintf("bonnie.%d", i)), bytesWritten)
	}
	newResult.WrittenBytes = 0
	for i := 0; i < bm.NumReadersWriters; i++ {
		result := <-bytesWritten
		if result.Error != nil {
			return result.Error
		}
		newResult.WrittenBytes += result.Result
	}
	newResult.WrittenDuration = time.Now().Sub(start)
	return nil
}
func (bm *Mark) RunSequentialReadTest() error {
	newResult := &bm.Results[len(bm.Results)-1]
	mem.ClearBufferCache()  
	bytesRead := make(chan ThreadResult)
	start := time.Now()
	for i := 0; i < bm.NumReadersWriters; i++ {
		go bm.singleThreadReadTest(path.Join(bm.BonnieDir, fmt.Sprintf("bonnie.%d", i)), bytesRead)
	}
	newResult.ReadBytes = 0
	for i := 0; i < bm.NumReadersWriters; i++ {
		result := <-bytesRead
		if result.Error != nil {
			return result.Error
		}
		newResult.ReadBytes += result.Result
	}
	newResult.ReadDuration = time.Now().Sub(start)
	return nil
}
func (bm *Mark) RunIOPSTest() error {
	newResult := &bm.Results[len(bm.Results)-1]
	mem.ClearBufferCache()  
	opsPerformed := make(chan ThreadResult)
	start := time.Now()
	for i := 0; i < bm.NumReadersWriters; i++ {
		go bm.singleThreadIOPSTest(path.Join(bm.BonnieDir, fmt.Sprintf("bonnie.%d", i)), opsPerformed)
	}
	newResult.IOOperations = 0
	for i := 0; i < bm.NumReadersWriters; i++ {
		result := <-opsPerformed
		if result.Error != nil {
			return result.Error
		}
		newResult.IOOperations += result.Result
	}
	newResult.IODuration = time.Now().Sub(start)
	return nil
}
func (bm Mark) MarshalJSON() ([]byte, error) {
	type Alias Mark
	return json.Marshal(&struct {
		Version string `json:"version"`
		Alias
	}{
		Version: Version,
		Alias:   Alias(bm),
	})
}
func (r Result) MarshalJSON() ([]byte, error) {
	type Alias Result
	return json.Marshal(&struct {
		WriteMBps       float64 `json:"write_megabytes_per_second"`
		ReadMBps        float64 `json:"read_megabytes_per_second"`
		IOPS            float64 `json:"iops"`
		WrittenDuration float64 `json:"write_seconds"`
		ReadDuration    float64 `json:"read_seconds"`
		IODuration      float64 `json:"io_seconds"`
		Alias
	}{
		WriteMBps:       MegaBytesPerSecond(r.WrittenBytes, r.WrittenDuration),
		ReadMBps:        MegaBytesPerSecond(r.ReadBytes, r.ReadDuration),
		IOPS:            IOPS(r.IOOperations, r.IODuration),
		WrittenDuration: r.WrittenDuration.Seconds(),
		ReadDuration:    r.ReadDuration.Seconds(),
		IODuration:      r.IODuration.Seconds(),
		Alias:           Alias(r),
	})
}
func ClearBufferCacheEveryThreeSeconds() error {
	for ; ; <-time.After(3 * time.Second) {
		err := mem.ClearBufferCache()
		if err != nil {
			return fmt.Errorf("Couldn't clear the buffer cache, bailing: %s", err)
		}
	}
}
func MegaBytesPerSecond(bytes int, duration time.Duration) float64 {
	return float64(bytes) / float64(duration.Seconds()) / 1000000
}
func IOPS(operations int, duration time.Duration) float64 {
	return float64(operations) / float64(duration.Seconds())
}