diff --git a/README.md b/README.md index 6eaaf47..fdd5d22 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## `bonniego` +## Go Bonnie Go! -`bonniego` is a _minimal_ implementation of Tim Bray's +`gobonniego` is a _minimal_ implementation of Tim Bray's [bonnie](https://code.google.com/p/bonnie-64/) written in Go (*bonnie* is written in C). @@ -12,29 +12,29 @@ It presents three disk metrics: 2. Sequential Read (higher is better) 3. IOPS (I/O Operations per Second) (higher is better) -## Getting `bonniego` +## Getting `gobonniego` -Easiest way to get `bonniego` is to download the pre-built binaries on the -[Releases](https://github.com/cunnie/bonniego/releases/). In the following +Easiest way to get `gobonniego` is to download the pre-built binaries on the +[Releases](https://github.com/cunnie/gobonniego/releases/). In the following example, we are logged into a Linux box and we download and run the Linux binary: ``` -curl -o bonniego -L https://github.com/cunnie/bonniego/releases/download/1.0.0/bonniego-linux-amd64 -chmod +x bonniego -./bonniego +curl -o gobonniego -L https://github.com/cunnie/gobonniego/releases/download/1.0.1/gobonniego-linux-amd64 +chmod +x gobonniego +./gobonniego ``` -Alternatively, you can build `bonniego` from source. +Alternatively, you can build `gobonniego` from source. [Here](https://gobyexample.com/command-line-arguments) is a good place to start. ## Examples -`bonniego` can be invoked without parameters; its defaults are reasonable. +`gobonniego` can be invoked without parameters; its defaults are reasonable. ``` -bonniego +gobonniego ``` Typical output: @@ -49,13 +49,13 @@ Running with the verbose option will print additional timestamped information to STDERR: ``` -bonniego -v +gobonniego -v ``` Yields: ``` -2018/02/12 08:05:02 Bonnie working directory: /var/folders/zp/vmj1nyzj6p567k5syt3hvq3h0000gn/T/bonniegoParent649139571/bonniego +2018/02/12 08:05:02 Bonnie working directory: /var/folders/zp/vmj1nyzj6p567k5syt3hvq3h0000gn/T/gobonniegoParent649139571/gobonniego 2018/02/12 08:05:02 Number of concurrent processes: 4 2018/02/12 08:05:02 Total System RAM (MiB): 16384 2018/02/12 08:05:03 Written (MiB): 1024 @@ -69,108 +69,108 @@ Sequential Read MiB/s: 6729.41 IOPS: 26156 ``` -You can tell `bonniego` where to place its test files. This is useful if the +You can tell `gobonniego` where to place its test files. This is useful if the default filesystem is too small or if you want to test a specific disk. -`bonniego` will clean up after itself, and will not delete the directory it's +`gobonniego` will clean up after itself, and will not delete the directory it's told to run in (you can safely specify `/tmp` or `/` as the directory). Here are some examples: ``` -bonniego -dir D:\ -bonniego -dir /tmp -bonniego -dir /zfs/tank +gobonniego -dir D:\ +gobonniego -dir /tmp +gobonniego -dir /zfs/tank ``` You may specify the number of threads (Goroutines) to run with the `-procs` flag. In this example, we spawn 8 threads: ``` -bonniego -procs 8 +gobonniego -procs 8 ``` -`-version` will display the current version of `bonniego`: +`-version` will display the current version of `gobonniego`: ``` -bonniego -version +gobonniego -version ``` Yields: ``` -bonniego version 1.0.0 +gobonniego version 1.0.0 ``` -`bonniego -h` will print out the available command line options and their +`gobonniego -h` will print out the available command line options and their current default values: ``` -Usage of ./bonniego: +Usage of ./gobonniego: -dir string - The directory in which bonniego places its temp files, should have at least twice system RAM available (default "/tmp/bonniegoParent139558072") + The directory in which gobonniego places its temp files, should have at least twice system RAM available (default "/tmp/gobonniegoParent139558072") -procs int The number of concurrent readers/writers, defaults to the number of CPU cores (default 8) -v Verbose. Will print to stderr diagnostic information such as the amount of RAM, number of cores, etc. -version - Version. Will print the current version of bonniego and then exit + Version. Will print the current version of gobonniego and then exit ``` ## Technical Notes -`bonniego` detects the number of CPU cores and the amount of RAM. +`gobonniego` detects the number of CPU cores and the amount of RAM. The number of cores may not match the number of physical cores. For example, an Intel core i5 with two physical cores and hyperthreading is detected as 4 cores. -`bonniego` spawns one thread for each core unless overridden by the `-procs` +`gobonniego` spawns one thread for each core unless overridden by the `-procs` flag. -`bonniego` writes twice the amount of RAM. For example, on a system with 16 -GiB of RAM, `bonniego` would write 32 GiB of data. This is to reduce the effect +`gobonniego` writes twice the amount of RAM. For example, on a system with 16 +GiB of RAM, `gobonniego` would write 32 GiB of data. This is to reduce the effect of the [buffer cache](http://www.tldp.org/LDP/sag/html/buffer-cache.html), which may give misleadingly good results. -`bonniego` divides the total amount to write by the number of threads. For +`gobonniego` divides the total amount to write by the number of threads. For example, a 4-core system with 8 GiB of RAM would have four threads each of which would concurrently write 4 GiB of data for a total of 16 GiB. -`bonniego` writes with buffered I/O; however, it waits for +`gobonniego` writes with buffered I/O; however, it waits for [`bufio.Flush()`](https://golang.org/pkg/bufio/#Writer.Flush) to complete before recording the duration. -`bonniego` creates a 64 kiB chunk of random data which it writes in succession +`gobonniego` creates a 64 kiB chunk of random data which it writes in succession to disk. It's random in order to avoid inflating the results for filesystems which enable compression (e.g. ZFS). -`bonniego` reads the files concurrently in 64 kiB chunks. Every 127 chunks it +`gobonniego` reads the files concurrently in 64 kiB chunks. Every 127 chunks it does a byte comparison against the original random data 64 kiB chunk to make sure there has been no corruption. This probably exacts a small penalty in read performance. -For IOPS measurement, a `bonniego` thread seeks to a random position in the +For IOPS measurement, a `gobonniego` thread seeks to a random position in the file and reads 512 bytes. This counts as a single operation. Every tenth seek instead of reading it will write 512 bytes of data. This also counts as an operation. The ratio of reads:writes is 10:1, in order to approximate the ratio that the TPC-E benchmark uses (). -`bonniego` uses [`ioutil.TempDir()`](https://golang.org/pkg/io/ioutil/#TempDir) +`gobonniego` uses [`ioutil.TempDir()`](https://golang.org/pkg/io/ioutil/#TempDir) to create the temporary directory in which to place its files, unless overridden by the `-dir` flag. On Linux systems this temporary directory is often `/tmp/`, on macOS systems, `/var/folders/...`. ## Bugs -If `bonniego` fills up the filesystem, it will crash and you will need to find -& delete the `bonniego` files manually. Below is a sample `find` command to -locate the `bonniego` directory; delete that directory and everything +If `gobonniego` fills up the filesystem, it will crash and you will need to find +& delete the `gobonniego` files manually. Below is a sample `find` command to +locate the `gobonniego` directory; delete that directory and everything underneath: ``` -find / -name bonniegoParent\* +find / -name gobonniegoParent\* ``` -`bonniego` doesn't work on FreeBSD yet; it depends on the +`gobonniego` doesn't work on FreeBSD yet; it depends on the [gosigar](https://github.com/cloudfoundry/gosigar) library which doesn't have the FreeBSD implementations for the calls that the determine the number of CPU cores and the amount of system RAM. @@ -190,9 +190,20 @@ it. And credit must be given to Brendan Gregg's excellent post, _[Active Benchmarking: Bonnie++](http://www.brendangregg.com/ActiveBenchmarking/bonnie++.html)_. + +### Name + +Tim Bray suggested the name, _gobonniego_: + +> maybe "GoBonnieGo"? + +It's a reference to the refrain of Chuck Berry's song, [Johnny B. +Goode](https://en.wikipedia.org/wiki/Johnny_B._Goode), which repeats the +phrase, "Go Johnny go" + ### Impetus -The impetus for writing `bonniego` is to provide concurrency. During a benchmark +The impetus for writing `gobonniego` is to provide concurrency. During a benchmark of a ZFS filesystem (using *bonnie++*), it became clear that a the single-threaded performance of *bonnie++* and not disk speed was the limiting factor. diff --git a/bin/make_all b/bin/make_all index 96cdd99..c73bd18 100755 --- a/bin/make_all +++ b/bin/make_all @@ -5,10 +5,10 @@ export GOOS GOARCH for GOOS in darwin linux; do for GOARCH in amd64; do - go build -o $GOPATH/bin/bonniego-$GOOS-$GOARCH bonniego.go + go build -o $GOPATH/bin/gobonniego-$GOOS-$GOARCH gobonniego.go done done # Windows has a custom extension GOOS=windows GOARCH=amd64 -go build -o $GOPATH/bin/bonniego-$GOOS-$GOARCH.exe bonniego.go +go build -o $GOPATH/bin/gobonniego-$GOOS-$GOARCH.exe gobonniego.go diff --git a/bonniego.go b/gobonniego.go similarity index 93% rename from bonniego.go rename to gobonniego.go index 0a82487..dc64f5d 100644 --- a/bonniego.go +++ b/gobonniego.go @@ -17,29 +17,29 @@ import ( "time" ) -const Version = "1.0.0" +const Version = "1.0.1" const Blocksize = 0x1 << 16 // 65,536 bytes, 2^16 bytes func main() { var bonnieTempDir, bonnieParentDir, bonnieDir string var numProcs int var verbose, version bool - bonnieTempDir, err := ioutil.TempDir("", "bonniegoParent") + bonnieTempDir, err := ioutil.TempDir("", "gobonniegoParent") check(err) defer os.RemoveAll(bonnieTempDir) flag.BoolVar(&verbose, "v", false, "Verbose. Will print to stderr diagnostic information such as the amount of RAM, number of cores, etc.") - flag.BoolVar(&version, "version", false, "Version. Will print the current version of bonniego and then exit") + flag.BoolVar(&version, "version", false, "Version. Will print the current version of gobonniego and then exit") flag.IntVar(&numProcs, "procs", runtime.NumCPU(), "The number of concurrent readers/writers, defaults to the number of CPU cores") - flag.StringVar(&bonnieParentDir, "dir", bonnieTempDir, "The directory in which bonniego places its temp files, should have at least twice system RAM available") + flag.StringVar(&bonnieParentDir, "dir", bonnieTempDir, "The directory in which gobonniego places its temp files, should have at least twice system RAM available") flag.Parse() if version { - fmt.Printf("bonniego version %s\n", Version) + fmt.Printf("gobonniego version %s\n", Version) os.Exit(0) } - // if bonnieParentDir exists, e.g. "/tmp", all is good, but if it doesn't, e.g. "/tmp/bonniego_run_five", then create it + // if bonnieParentDir exists, e.g. "/tmp", all is good, but if it doesn't, e.g. "/tmp/gobonniego_run_five", then create it fileInfo, err := os.Stat(bonnieParentDir) if err != nil { err = os.Mkdir(bonnieParentDir, 0755) @@ -50,7 +50,7 @@ func main() { panic(fmt.Sprintf("'%s' is not a directory!", bonnieParentDir)) } - bonnieDir = path.Join(bonnieParentDir, "bonniego") + bonnieDir = path.Join(bonnieParentDir, "gobonniego") err = os.Mkdir(bonnieDir, 0755) check(err) defer os.RemoveAll(bonnieDir)