Go Concurrency Benchmarking on a Raspberry Pi


In hindsight, no one claimed that a Raspberry Pi of any model was a powerhouse machine. However, I had thoughts about how to benchmark computing power after leaving Dreamhost and noticing that even tar and gzipping my WordPress installs performed like an ancient machine despite the processor statistics. That made me think about a raw benchmarking metric that could deployed anywhere. I was also learning Go and trying to understand Go concurrency. I ended up with a “concurrency” of 2 because the lower power systems didn’t get any more out of an additional goroutine.


package main
import (
"encoding/base64"
"fmt"
"golang.org/x/crypto/sha3"
"strings"
"time"
)
func main() {
var before string
var after [64]byte
var base64Encoding string
var result chan string = make(chan string)
var resultString string
var addOnStart int64
start := time.Now()
addOn := 0
concurrency := 2
sem := make(chan bool, concurrency)
for {
before = fmt.Sprintf("Message%d", addOn)
after = sha3.Sum512([]byte(before))
base64Encoding = base64.StdEncoding.EncodeToString(after[:])
if strings.HasPrefix(base64Encoding, "TEST") {
fmt.Printf("%d seconds\n", int64(time.Since(start)/time.Second))
break
}
addOn++
}
fmt.Printf("%d: %s\n", addOn, base64Encoding)
addOnStart = 0
start = time.Now()
SEARCHY:
for {
sem <- true
go scan1000000(addOnStart, result, sem)
select {
case resultString, _ = <-result:
break SEARCHY
default:
}
addOnStart++
}
fmt.Printf("%d seconds\n", int64(time.Since(start)/time.Second))
fmt.Print(resultString)
}
func scan1000000(addOnStart int64, result chan string, sem chan bool) {
var before string
var after [64]byte
var base64Encoding string
defer func() { <-sem }()
for i := addOnStart * 1000000; i < (addOnStart+1)*1000000; i++ {
before = fmt.Sprintf("Message%d", i)
after = sha3.Sum512([]byte(before))
base64Encoding = base64.StdEncoding.EncodeToString(after[:])
if strings.HasPrefix(base64Encoding, "TEST") {
result <- fmt.Sprintf("%d: %s\n", i, base64Encoding)
break
}
}
}

view raw

gosha3.go

hosted with ❤ by GitHub

The program requires 13,135,013 sha3 hashes and conversions to base 64 to come up with a string that starts with “TEST”.

My work workstation’s output:

[Specs: Late 2013 Retina MacBook Pro 15″, 2.3 GHz Core i7 – (I7-4850HQ)]

  • Single thread: 16 seconds
  • Concurrency of two: 10 seconds
  • Compared with PassMark:
    • 9066
    • Single thread 1964

A Late 2011 MacBook Pro 13″, 2.4 GHz Core i5 (I5-2435M):

  • Single thread: 34 seconds
  • Concurrency of two: 19 seconds
  • Compared with PassMark:
    • 3269
    • Single Thread 1347

A Core i3-5010U 2.10 GHz NUC (Windows 10 Pro)

  • Single thread: 27 seconds
  • Concurrency of two: 17 seconds
  • Compared with PassMark:
    • 3060
    • Single Thread 1171

A Mid 2009 MacBook Pro 13″, 2.26 GHz Core 2 Duo (P7550)

  • Single thread: 57 seconds (Originally was 83 on go1.3.3, but better results with 1.8.3)
  • Concurrency of two: 32 seconds (Originally was 80 on go1.3.3)
  • Compared with PassMark:
    • 1521
    • Single Thread 892

A ThinkPad 11e with A4-6210 APU (1.8 GHz – Windows 10 Home)

  • Single thread: 135 seconds
  • Concurrency of two: 65 seconds
  • Compared with PassMark:
    • 2143
    • Single Thread 697

Raspberry Pi 3B

  • Single thread: 1265 seconds
  • Concurrency of two: heat warnings!

For the purposes of this “performance” benchmark, there is definitely a non-linear relationship between a canned benchmark score and the score in a brute force operation that has a heavy calculation component. I’m also isolating only one aspect of system performance. There is a SATA SSD on the newest machine, a SATA HDD on the 2011 and 2009 machines, and an SD card on the Raspberry Pi. The RAM is different in every machine as well. Still, it was a fun experiment that motivated me to spend a little extra time in Go and learning Go Concurrency.


%d bloggers like this: