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