package main
import (
"flag"
"fmt"
"math/rand"
"os"
"runtime"
"runtime/pprof"
"sync"
"syscall"
"time"
"unsafe"
)
func cpu() uint64
var cpus map[uint64]
int
func init() {
cpus = make(map[uint64]
int
)
var aff uint64
syscall.Syscall(syscall.SYS_SCHED_GETAFFINITY, uintptr(0), unsafe.Sizeof(aff), uintptr(unsafe.Pointer(&aff)))
n := 0
start :=
time
.Now()
var mask uint64 = 1
Outer:
for
{
for
(aff & mask) == 0 {
mask <<= 1
if
mask == 0 || mask > aff {
break
Outer
}
}
ret, _, err := syscall.Syscall(syscall.SYS_SCHED_SETAFFINITY, uintptr(0), unsafe.Sizeof(mask), uintptr(unsafe.Pointer(&mask)))
if
ret != 0 {
panic(err.Error())
}
<-
time
.After(1 *
time
.Millisecond)
c := cpu()
if
oldn, ok := cpus[c]; ok {
fmt.Println(
"cpu"
, n,
"=="
, oldn,
"-- both have CPUID"
, c)
}
cpus[c] = n
mask <<= 1
n++
}
fmt.Printf(
"%d/%d cpus found in %v: %v\n"
, len(cpus), runtime.NumCPU(),
time
.Now().Sub(start), cpus)
ret, _, err := syscall.Syscall(syscall.SYS_SCHED_SETAFFINITY, uintptr(0), unsafe.Sizeof(aff), uintptr(unsafe.Pointer(&aff)))
if
ret != 0 {
panic(err.Error())
}
}
type RWMutex2 []sync.RWMutex
func (mx RWMutex2) Lock() {
for
core := range mx {
mx[core].Lock()
}
}
func (mx RWMutex2) Unlock() {
for
core := range mx {
mx[core].Unlock()
}
}
func main() {
cpuprofile := flag.Bool(
"cpuprofile"
,
false
,
"enable CPU profiling"
)
locks := flag.Uint64(
"i"
, 10000,
"Number of iterations to perform"
)
write := flag.Float64(
"p"
, 0.0001,
"Probability of write locks"
)
wwork := flag.Int(
"w"
, 1,
"Amount of work for each writer"
)
rwork := flag.Int(
"r"
, 100,
"Amount of work for each reader"
)
readers := flag.Int(
"n"
, runtime.GOMAXPROCS(0),
"Total number of readers"
)
checkcpu := flag.Uint64(
"c"
, 100,
"Update CPU estimate every n iterations"
)
flag.Parse()
var o *os.File
if
*cpuprofile {
o, _ := os.Create(
"rw.out"
)
pprof.StartCPUProfile(o)
}
readers_per_core := *readers / runtime.GOMAXPROCS(0)
var wg sync.WaitGroup
var mx1 sync.RWMutex
start1 :=
time
.Now()
for
n := 0; n < runtime.GOMAXPROCS(0); n++ {
for
r := 0; r < readers_per_core; r++ {
wg.Add(1)
go func() {
defer wg.Done()
r :=
rand
.New(
rand
.NewSource(
rand
.Int63()))
for
n := uint64(0); n < *locks; n++ {
if
r.Float64() < *write {
mx1.Lock()
x := 0
for
i := 0; i < *wwork; i++ {
x++
}
_ = x
mx1.Unlock()
}
else
{
mx1.RLock()
x := 0
for
i := 0; i < *rwork; i++ {
x++
}
_ = x
mx1.RUnlock()
}
}
}()
}
}
wg.Wait()
end1 :=
time
.Now()
t1 := end1.Sub(start1)
fmt.Println(
"mx1"
, runtime.GOMAXPROCS(0), *readers, *locks, *write, *wwork, *rwork, *checkcpu, t1.Seconds(), t1)
if
*cpuprofile {
pprof.StopCPUProfile()
o.Close()
o, _ = os.Create(
"rw2.out"
)
pprof.StartCPUProfile(o)
}
mx2 := make(RWMutex2, len(cpus))
start2 :=
time
.Now()
for
n := 0; n < runtime.GOMAXPROCS(0); n++ {
for
r := 0; r < readers_per_core; r++ {
wg.Add(1)
go func() {
defer wg.Done()
c := cpus[cpu()]
r :=
rand
.New(
rand
.NewSource(
rand
.Int63()))
for
n := uint64(0); n < *locks; n++ {
if
*checkcpu != 0 && n%*checkcpu == 0 {
c = cpus[cpu()]
}
if
r.Float64() < *write {
mx2.Lock()
x := 0
for
i := 0; i < *wwork; i++ {
x++
}
_ = x
mx2.Unlock()
}
else
{
mx2[c].RLock()
x := 0
for
i := 0; i < *rwork; i++ {
x++
}
_ = x
mx2[c].RUnlock()
}
}
}()
}
}
wg.Wait()
end2 :=
time
.Now()
pprof.StopCPUProfile()
o.Close()
t2 := end2.Sub(start2)
fmt.Println(
"mx2"
, runtime.GOMAXPROCS(0), *readers, *locks, *write, *wwork, *rwork, *checkcpu, t2.Seconds(), t2)
}