158 lines
2.7 KiB
Go
158 lines
2.7 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"runtime"
|
||
|
"sync"
|
||
|
"time"
|
||
|
"unsafe"
|
||
|
|
||
|
"git.wow.st/gmp/nswrap/examples/strings/ns"
|
||
|
)
|
||
|
|
||
|
func incr() func(bool) (int, float64) {
|
||
|
i := 0
|
||
|
b := 0.0
|
||
|
var mx sync.Mutex
|
||
|
return func(bad bool) (int, float64) {
|
||
|
mx.Lock()
|
||
|
if bad {
|
||
|
b++
|
||
|
defer mx.Unlock()
|
||
|
} else {
|
||
|
defer func() { i++; mx.Unlock() }()
|
||
|
}
|
||
|
if b == 0 {
|
||
|
return i, 0.0
|
||
|
} else {
|
||
|
return i, (b/float64(i)) * 100
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type tracker struct {
|
||
|
add, drop func(*ns.Id)
|
||
|
check func()
|
||
|
i func(bool) (int, float64)
|
||
|
}
|
||
|
|
||
|
type record struct {
|
||
|
ptr unsafe.Pointer
|
||
|
goPtr *ns.Id
|
||
|
when time.Time
|
||
|
}
|
||
|
|
||
|
func newTracker() (func(*ns.Id), func(*ns.Id), func()) {
|
||
|
addch := make(chan *ns.Id)
|
||
|
dropch := make(chan *ns.Id)
|
||
|
data := []record{}
|
||
|
var mux sync.Mutex
|
||
|
|
||
|
go func() {
|
||
|
for {
|
||
|
select {
|
||
|
case x := <-addch:
|
||
|
mux.Lock()
|
||
|
data = append(data,record{
|
||
|
x.Ptr(),
|
||
|
x,
|
||
|
time.Now(),
|
||
|
})
|
||
|
mux.Unlock()
|
||
|
case x := <-dropch:
|
||
|
mux.Lock()
|
||
|
data = append(data,record{
|
||
|
nil,
|
||
|
x,
|
||
|
time.Now(),
|
||
|
})
|
||
|
mux.Unlock()
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
add := func(x *ns.Id) {
|
||
|
addch<- x
|
||
|
}
|
||
|
drop := func(x *ns.Id) {
|
||
|
dropch<- x
|
||
|
}
|
||
|
check := func() {
|
||
|
live := map[unsafe.Pointer]*ns.Id{}
|
||
|
bad := false
|
||
|
mux.Lock()
|
||
|
for _,r := range data {
|
||
|
if r.ptr != nil {
|
||
|
if live[r.ptr] != nil {
|
||
|
fmt.Printf("COLLISION: %p & %p -> %p\n", r.goPtr, live[r.ptr], r.ptr)
|
||
|
bad = true
|
||
|
}
|
||
|
live[r.ptr] = r.goPtr
|
||
|
} else {
|
||
|
delete(live,r.ptr)
|
||
|
}
|
||
|
}
|
||
|
fmt.Printf("Checked %d records -- ",len(data))
|
||
|
if bad {
|
||
|
fmt.Printf("failed\n")
|
||
|
} else {
|
||
|
fmt.Printf("ok\n")
|
||
|
}
|
||
|
mux.Unlock()
|
||
|
}
|
||
|
return add,drop,check
|
||
|
}
|
||
|
|
||
|
func mkstrings(t tracker) {
|
||
|
for {
|
||
|
//fmt.Printf("main thread: %t\n",ns.NSThreadIsMainThread())
|
||
|
x,b := t.i(false)
|
||
|
str := fmt.Sprintf("string %d",x)
|
||
|
s := ns.NSStringWithGoString(str)
|
||
|
//t.add(&s.Id)
|
||
|
for j := 0; j < 10; j++ {
|
||
|
sout := s.String()
|
||
|
if str != sout {
|
||
|
_,b = t.i(true)
|
||
|
fmt.Printf("%3.2f%% -- %d: '%s' '%s'\n", b, x, str, sout)
|
||
|
}
|
||
|
time.Sleep(time.Second/1000)
|
||
|
}
|
||
|
if x % 1000 == 0 {
|
||
|
fmt.Printf("%3.2f%% -- %s\n", b, time.Now().Format("03:04:05.000"))
|
||
|
}
|
||
|
//t.drop(&s.Id)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
runtime.GOMAXPROCS(4)
|
||
|
fmt.Printf("Starting\n")
|
||
|
//ns.NSThreadNew().Start()
|
||
|
fmt.Printf("multithreaded: %t\n", ns.NSThreadIsMultiThreaded())
|
||
|
//pool := ns.NSAutoreleasePoolAlloc()
|
||
|
add, drop, check := newTracker()
|
||
|
i := tracker{add, drop, check, incr()}
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go mkstrings(i)
|
||
|
go func() {
|
||
|
for {
|
||
|
runtime.GC()
|
||
|
time.Sleep(time.Second/100)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
time.Sleep(time.Second * 600)
|
||
|
i.check()
|
||
|
|
||
|
//pool.Drain()
|
||
|
os.Exit(0)
|
||
|
}
|