diff --git a/go/callgraph/callgraph_test.go b/go/callgraph/callgraph_test.go index 907b317a0c2..225656641ac 100644 --- a/go/callgraph/callgraph_test.go +++ b/go/callgraph/callgraph_test.go @@ -27,16 +27,15 @@ import ( // Current results were on an i7 macbook on go version devel go1.20-2730. // Number of nodes, edges, and reachable function are expected to vary between // go versions. Timing results are expected to vary between machines. -// // BenchmarkStatic-12 53 ms/op 6 MB/op 12113 nodes 37355 edges 1522 reachable // BenchmarkCHA-12 86 ms/op 16 MB/op 12113 nodes 131717 edges 7640 reachable // BenchmarkRTA-12 110 ms/op 12 MB/op 6566 nodes 42291 edges 5099 reachable // BenchmarkPTA-12 1427 ms/op 600 MB/op 8714 nodes 28244 edges 4184 reachable -// BenchmarkVTA-12 603 ms/op 87 MB/op 12112 nodes 44857 edges 4918 reachable -// BenchmarkVTA2-12 774 ms/op 115 MB/op 4918 nodes 20247 edges 3841 reachable -// BenchmarkVTA3-12 928 ms/op 134 MB/op 3841 nodes 16502 edges 3542 reachable -// BenchmarkVTAAlt-12 395 ms/op 61 MB/op 7640 nodes 29629 edges 4257 reachable -// BenchmarkVTAAlt2-12 556 ms/op 82 MB/op 4257 nodes 18057 edges 3586 reachable +// BenchmarkVTA-12 562 ms/op 78 MB/op 12112 nodes 44857 edges 4918 reachable +// BenchmarkVTA2-12 743 ms/op 103 MB/op 4918 nodes 20247 edges 3841 reachable +// BenchmarkVTA3-12 837 ms/op 119 MB/op 3841 nodes 16502 edges 3542 reachable +// BenchmarkVTAAlt-12 356 ms/op 56 MB/op 7640 nodes 29629 edges 4257 reachable +// BenchmarkVTAAlt2-12 490 ms/op 75 MB/op 4257 nodes 18057 edges 3586 reachable // // Note: // * Static is unsound and may miss real edges. diff --git a/go/callgraph/vta/propagation.go b/go/callgraph/vta/propagation.go index 6127780ac4e..5817e89380f 100644 --- a/go/callgraph/vta/propagation.go +++ b/go/callgraph/vta/propagation.go @@ -20,53 +20,52 @@ import ( // with ids X and Y s.t. X < Y, Y comes before X in the topological order. func scc(g vtaGraph) (map[node]int, int) { // standard data structures used by Tarjan's algorithm. - var index uint64 + type state struct { + index int + lowLink int + onStack bool + } + states := make(map[node]*state, len(g)) var stack []node - indexMap := make(map[node]uint64) - lowLink := make(map[node]uint64) - onStack := make(map[node]bool) - nodeToSccID := make(map[node]int) + nodeToSccID := make(map[node]int, len(g)) sccID := 0 var doSCC func(node) doSCC = func(n node) { - indexMap[n] = index - lowLink[n] = index - index = index + 1 - onStack[n] = true + index := len(states) + ns := &state{index: index, lowLink: index, onStack: true} + states[n] = ns stack = append(stack, n) for s := range g[n] { - if _, ok := indexMap[s]; !ok { + if ss, visited := states[s]; !visited { // Analyze successor s that has not been visited yet. doSCC(s) - lowLink[n] = min(lowLink[n], lowLink[s]) - } else if onStack[s] { + ss = states[s] + ns.lowLink = min(ns.lowLink, ss.lowLink) + } else if ss.onStack { // The successor is on the stack, meaning it has to be // in the current SCC. - lowLink[n] = min(lowLink[n], indexMap[s]) + ns.lowLink = min(ns.lowLink, ss.index) } } // if n is a root node, pop the stack and generate a new SCC. - if lowLink[n] == indexMap[n] { - for { - w := stack[len(stack)-1] + if ns.lowLink == index { + var w node + for w != n { + w = stack[len(stack)-1] stack = stack[:len(stack)-1] - onStack[w] = false + states[w].onStack = false nodeToSccID[w] = sccID - if w == n { - break - } } sccID++ } } - index = 0 for n := range g { - if _, ok := indexMap[n]; !ok { + if _, visited := states[n]; !visited { doSCC(n) } } @@ -74,7 +73,7 @@ func scc(g vtaGraph) (map[node]int, int) { return nodeToSccID, sccID } -func min(x, y uint64) uint64 { +func min(x, y int) int { if x < y { return x }