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)
}