func prepare() { // group objects by type fmt.Println("Grouping by type...") byType = make([]bucket, len(d.FTList)) for i := 0; i < d.NumObjects(); i++ { x := read.ObjId(i) tid := d.Ft(x).Id b := byType[tid] b.bytes += d.Size(x) b.objects = append(b.objects, x) byType[tid] = b } // compute referrers fmt.Println("Computing referrers...") ref1 = make([]read.ObjId, d.NumObjects()) for i := 0; i < d.NumObjects(); i++ { ref1[i] = read.ObjNil } ref2 = map[read.ObjId][]read.ObjId{} for i := 0; i < d.NumObjects(); i++ { x := read.ObjId(i) //fmt.Printf("object %d %x %d %s %s\n", i, d.Addr(x), d.Size(x), d.Ft(x).GCSig, d.Ft(x).Name) //printbytes(d.Contents(x)) for _, e := range d.Edges(x) { r := ref1[e.To] if r == read.ObjNil { ref1[e.To] = x } else if x != r { s := ref2[e.To] if len(s) == 0 || x != s[len(s)-1] { ref2[e.To] = append(s, x) } } } } dom() }
func objHandler(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() v := q["id"] if len(v) != 1 { http.Error(w, "id parameter missing", 405) return } id, err := strconv.ParseUint(v[0], 10, 64) if err != nil { http.Error(w, err.Error(), 405) return } if int(id) >= d.NumObjects() { http.Error(w, "object not found", 405) return } x := read.ObjId(id) fld := getFields(d.Contents(x), d.Ft(x).Fields, d.Edges(x)) if len(fld) > maxFields { msg := fmt.Sprintf("<font color=Red>elided for display: %d fields</font>", len(fld)-(maxFields-1)) fld = fld[:maxFields-1] fld = append(fld, Field{msg, "", ""}) } ref := getReferrers(x) if len(ref) > maxFields { msg := fmt.Sprintf("<font color=Red>elided for display: %d referrers</font>", len(ref)-(maxFields-1)) ref = ref[:maxFields-1] ref = append(ref, msg) } info := objInfo{ d.Addr(x), typeLink(d.Ft(x)), d.Size(x), fld, ref, domsize[x], } if err := objTemplate.Execute(w, info); err != nil { log.Print(err) } }
func dom() { fmt.Println("Computing dominators...") n := d.NumObjects() // make list of roots // TODO: have loader compute this? roots := map[read.ObjId]struct{}{} for _, s := range []*read.Data{d.Data, d.Bss} { for _, e := range s.Edges { roots[e.To] = struct{}{} } } for _, f := range d.Frames { for _, e := range f.Edges { roots[e.To] = struct{}{} } } for _, x := range d.Otherroots { for _, e := range x.Edges { roots[e.To] = struct{}{} } } // compute postorder traversal // object states: // 0 - not seen yet // 1 - seen, added to queue, not yet expanded children // 2 - seen, already expanded children // 3 - added to postorder postorder := make([]read.ObjId, 0, n) postnum := make([]int, n+1) state := make([]byte, n) var q []read.ObjId // stack of work to do, holds state 1 and 2 objects for x := range roots { if state[x] != 0 { if state[x] != 3 { log.Fatal("bad state found") } continue } state[x] = 1 q = q[:0] q = append(q, x) for len(q) > 0 { y := q[len(q)-1] if state[y] == 2 { state[y] = 3 q = q[:len(q)-1] postnum[y] = len(postorder) postorder = append(postorder, y) } else { if state[y] != 1 { log.Fatal("bad state") } state[y] = 2 for _, e := range d.Edges(y) { z := e.To if state[z] == 0 { state[z] = 1 q = append(q, z) } } } } } postnum[n] = n // virtual start node // compute immediate dominators // http://www.hipersoft.rice.edu/grads/publications/dom14.pdf idom := make([]read.ObjId, n+1) for i := 0; i < n; i++ { idom[i] = read.ObjNil } idom[n] = read.ObjId(n) for r := range roots { idom[r] = read.ObjId(n) } var redges []read.ObjId change := true for change { change = false for i := len(postorder) - 1; i >= 0; i-- { x := postorder[i] // get list of incoming edges redges = redges[:0] if ref1[x] != read.ObjNil { redges = append(redges, ref1[x]) redges = append(redges, ref2[x]...) } a := read.ObjNil for _, b := range redges { if idom[b] == read.ObjNil { continue } if a == read.ObjNil { a = b continue } for a != b { if postnum[a] < postnum[b] { a = idom[a] } else { b = idom[b] } } } if _, ok := roots[x]; ok { a = read.ObjId(n) } if a != idom[x] { idom[x] = a change = true } } } domsize = make([]uint64, n+1) for _, x := range postorder { domsize[x] += d.Size(x) domsize[idom[x]] += domsize[x] } // Note: unreachable objects will have domsize of 0. }