This is a Go library that implements synchronization primitives over Intel TSX (hardware transactional primitives).
go get github.com/linux4life798/safetyfastCheckout the SafetyFast Project Page.
The following plot shows the number of milliseconds it took for 8 goroutines to increments 480000 random elements (per goroutine) of an array of ints. The x axis denotes how large (and therefore sparse) the array was. The synchronization primitive used during the increment is indicated as a series/line.
Note that, as the array size increases, the likelihood of two goroutines touching the same element at the same instance decreases. This is why we see such a dramatic increase in speed, when using either the HLE or RTM style synchronization primitive.
The SystemMutex is just sync.Mutex.
It is also worth observing that the performance started to degrade towards the very large array sizes. This is most likely due to a cache size limitation.
m := map[string]int{
"word1": 0,
}
c := NewRTMContexDefault()
c.Atomic(func() {
// Action to be done transactionally
m["word1"] = m["word1"] + 1
})m := map[string]int{
"word1": 0,
}
var lock safetyfast.SpinHLEMutex
lock.Lock()
// Action to be done transactionally
m["word1"] = m["word1"] + 1
lock.Unlock()go get github.com/linux4life798/safetyfast/doihavetsx
doihavetsxThe output should look something like:
CPU Brand: Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
RTM: Yes
HLE: Yes
| CPU Name | CPU Codename / Generation | TSX Supported | Machine Description |
|---|---|---|---|
| Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz | Skylake/6th | Yes | Dell Precision 5510 |
| Intel(R) Xeon(R) Gold 6136 CPU @ 3.00GHz | Skylake/6th | Yes | Dell Precision 7920 |
| Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz | Ivy Bridge/3rd | No | MacBook Pro (Retina, Mid 2012) |
| Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz | Kaby Lake/7th | Yes | MacBook Pro "Core i7" 2.9 15" Touch/Mid-2017 |
| Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz | Haswell/4th | No (Yes-before microcode install) | MacBook Air (13-inch, Early 2014) |
| Intel(R) Core(TM) i7-7Y75 CPU @ 1.30GHz | Kaby Lake/7th | Yes | MacBook (Retina, 12-inch, 2017) |
| Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz | Haswell/4th | No | MacBook Pro (Retina, 15-inch, Mid 2015) |
| Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz | Kaby Lake/7th | Yes | MacBook Pro (15-inch, 2017) |
Please add your machine to this table! Pull-request or issues welcome.
It is necessary to check that the CPU you are using support Intel RTM and/or
Intel HLE instruction sets, since safetyfast does not check.
This can be accomplished by using the Intel provided cpuid package, as shown
below.
import (
"github.com/intel-go/cpuid"
)
func main() {
if !cpuid.HasExtendedFeature(cpuid.RTM) {
panic("The CPU does not support Intel RTM")
}
if !cpuid.HasExtendedFeature(cpuid.HLE) {
panic("The CPU does not support Intel HLE")
}
}package main
import (
"fmt"
"sync"
"github.com/linux4life798/safetyfast"
)
func main() {
m := map[string]int{
"word1": 0,
"word2": 0,
}
c := safetyfast.NewRTMContexDefault()
var wg sync.WaitGroup
wg.Add(2)
go c.Atomic(func() {
// Action to be done transactionally
m["word1"] = m["word1"] + 1
wg.Done()
})
go c.Atomic(func() {
// Action to be done transactionally
m["word1"] = m["word1"] + 1
wg.Done()
})
wg.Wait()
fmt.Println("word1 =", m["word1"])
}package main
import (
"fmt"
"sync"
"github.com/linux4life798/safetyfast"
)
func main() {
m := map[string]int{
"word1": 0,
"word2": 0,
}
var lock safetyfast.SpinHLEMutex
var wg sync.WaitGroup
wg.Add(2)
go func() {
lock.Lock()
// Action to be done transactionally
m["word1"] = m["word1"] + 1
lock.Unlock()
wg.Done()
}()
go func() {
lock.Lock()
// Action to be done transactionally
m["word1"] = m["word1"] + 1
lock.Unlock()
wg.Done()
}()
wg.Wait()
fmt.Println("word1 =", m["word1"])
}