5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-25 11:41:34 +00:00
yggdrasil-go/misc/sim/treesim-basic.go
2018-01-04 22:37:51 +00:00

198 lines
4.7 KiB
Go

package main
import "fmt"
import "bufio"
import "os"
import "strings"
import "strconv"
import "time"
import "runtime/pprof"
import "flag"
import "router"
////////////////////////////////////////////////////////////////////////////////
type Node struct {
nodeID router.NodeID
table router.Table
links []*Node
}
func (n *Node) init(nodeID router.NodeID) {
n.nodeID = nodeID
n.table.Init(nodeID)
n.links = append(n.links, n)
}
func linkNodes(m, n *Node) {
for _, o := range m.links {
if o.nodeID == n.nodeID {
// Don't allow duplicates
return
}
}
m.links = append(m.links, n)
n.links = append(n.links, m)
}
func makeStoreSquareGrid(sideLength int) map[router.NodeID]*Node {
store := make(map[router.NodeID]*Node)
nNodes := sideLength * sideLength
nodeIDs := make([]router.NodeID, 0, nNodes)
// TODO shuffle nodeIDs
for nodeID := 1; nodeID <= nNodes; nodeID++ {
nodeIDs = append(nodeIDs, router.NodeID(nodeID))
}
for _, nodeID := range nodeIDs {
node := &Node{}
node.init(nodeID)
store[nodeID] = node
}
for idx := 0; idx < nNodes; idx++ {
if (idx % sideLength) != 0 {
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-1]])
}
if idx >= sideLength {
linkNodes(store[nodeIDs[idx]], store[nodeIDs[idx-sideLength]])
}
}
return store
}
func loadGraph(path string) map[router.NodeID]*Node {
f, err := os.Open(path)
if err != nil {
panic(err)
}
defer f.Close()
store := make(map[router.NodeID]*Node)
s := bufio.NewScanner(f)
for s.Scan() {
line := s.Text()
nodeIDstrs := strings.Split(line, " ")
nodeIDi0, _ := strconv.Atoi(nodeIDstrs[0])
nodeIDi1, _ := strconv.Atoi(nodeIDstrs[1])
nodeID0 := router.NodeID(nodeIDi0)
nodeID1 := router.NodeID(nodeIDi1)
if store[nodeID0] == nil {
node := &Node{}
node.init(nodeID0)
store[nodeID0] = node
}
if store[nodeID1] == nil {
node := &Node{}
node.init(nodeID1)
store[nodeID1] = node
}
linkNodes(store[nodeID0], store[nodeID1])
}
return store
}
////////////////////////////////////////////////////////////////////////////////
func idleUntilConverged(store map[router.NodeID]*Node) {
timeOfLastChange := 0
step := 0
// Idle untl the network has converged
for step-timeOfLastChange < 4*router.TIMEOUT {
step++
fmt.Println("Step:", step, "--", "last change:", timeOfLastChange)
for _, node := range store {
node.table.Tick()
for idx, link := range node.links[1:] {
msg := node.table.CreateMessage(router.Iface(idx))
for idx, fromNode := range link.links {
if fromNode == node {
//fmt.Println("Sending from node", node.nodeID, "to", link.nodeID)
link.table.HandleMessage(msg, router.Iface(idx))
break
}
}
}
}
//for _, node := range store {
// if node.table.DEBUG_isDirty() { timeOfLastChange = step }
//}
//time.Sleep(10*time.Millisecond)
}
}
func testPaths(store map[router.NodeID]*Node) {
nNodes := len(store)
nodeIDs := make([]router.NodeID, 0, nNodes)
for nodeID := range store {
nodeIDs = append(nodeIDs, nodeID)
}
lookups := 0
count := 0
start := time.Now()
for _, source := range store {
count++
fmt.Printf("Testing paths from node %d / %d (%d)\n", count, nNodes, source.nodeID)
for _, dest := range store {
//if source == dest { continue }
destLoc := dest.table.GetLocator()
temp := 0
for here := source; here != dest; {
temp++
if temp > 16 {
panic("Loop?")
}
next := here.links[here.table.Lookup(destLoc)]
if next == here {
//for idx, link := range here.links {
// fmt.Println("DUMP:", idx, link.nodeID)
//}
panic(fmt.Sprintln("Routing Loop:",
source.nodeID,
here.nodeID,
dest.nodeID))
}
//fmt.Println("DEBUG:", source.nodeID, here.nodeID, dest.nodeID)
here = next
lookups++
}
}
}
timed := time.Since(start)
fmt.Printf("%f lookups per second\n", float64(lookups)/timed.Seconds())
}
func dumpStore(store map[router.NodeID]*Node) {
for _, node := range store {
fmt.Println("DUMPSTORE:", node.nodeID, node.table.GetLocator())
node.table.DEBUG_dumpTable()
}
}
////////////////////////////////////////////////////////////////////////////////
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
panic(fmt.Sprintf("could not create CPU profile: ", err))
}
if err := pprof.StartCPUProfile(f); err != nil {
panic(fmt.Sprintf("could not start CPU profile: ", err))
}
defer pprof.StopCPUProfile()
}
fmt.Println("Test")
store := makeStoreSquareGrid(4)
idleUntilConverged(store)
dumpStore(store)
testPaths(store)
//panic("DYING")
store = loadGraph("hype-2016-09-19.list")
idleUntilConverged(store)
dumpStore(store)
testPaths(store)
}