devtools/src/jehanne/cmd/op2/op2.go

108 lines
2.6 KiB
Go

package main
import (
"encoding/binary"
"fmt"
"io"
"os"
)
/*
first word
high 8 bits is ee, which is an invalid address on amd64.
next 8 bits is protocol version
next 16 bits is unused, MBZ. Later, we can make it a packet type.
next 16 bits is core id
next 8 bits is unused
next 8 bits is # words following.
second word is time in ns. (soon to be tsc ticks)
Third and following words are PCs, there must be at least one of them.
*/
type sample struct {
Wordcount, _ uint8
Coreid uint16
_ uint16
Version, Marker uint8
Ns uint64
}
type backtrace struct {
Pcs []uint64
}
/* the docs lie. Perl expects Count to be zero. I only wasted a day figuring this out. */
type hdr struct {
Count, Slots, Format, Period, Padding uint64
}
type record struct {
Count, Size uint64
Pcs []uint64
}
type trailer struct {
Zero, One, Zeroh uint64
}
func main() {
var s sample
r := io.Reader(os.Stdin)
w := io.Writer(os.Stdout)
records := make(map[string]uint64, 16384)
backtraces := make(map[string][]uint64, 1024)
/* ignore the documentation, it's wrong, first word must be zero.
* the perl code that figures word length depends on it.
*/
hdr := hdr{0, 3, 0, 10000, 0}
trailer := trailer{0, 1, 0}
start := uint64(0)
end := start
nsamples := end
for binary.Read(r, binary.LittleEndian, &s) == nil {
numpcs := int(s.Wordcount)
bt := make([]uint64, numpcs)
binary.Read(r, binary.LittleEndian, &bt)
//fmt.Printf("%v\n", bt)
record := ""
/* Fix the symbols. pprof was unhappy about the 0xfffffff.
* N.B. The fact that we have to mess with the bt values
* is the reason we did not write a stringer for bt.
*/
for i := range bt {
bt[i] = bt[i] & ((uint64(1) << 32) - 1)
record = record + fmt.Sprintf("0x%x ", bt[i])
}
records[record]++
backtraces[record] = bt
//fmt.Printf("%v %d %d %x %v record %v\n", s, s.Wordcount, s.Coreid, s.Ns, bt, record)
/* how sad, once we go to ticks this gets ugly. */
if start == 0 {
start = s.Ns
}
end = s.Ns
nsamples++
}
/* we'll need to fix this once we go to ticks. */
hdr.Period = (end - start) / nsamples
hdr.Count = uint64(0) // !@$@!#$!@#$len(records))
//fmt.Printf("start %v end %v nsamples %d period %d\n", start, end, nsamples, hdr.Period)
binary.Write(w, binary.LittleEndian, &hdr)
out := make([]uint64, 2)
/* note that the backtrace length varies. But we're good with that. */
for key, v := range records {
bt := backtraces[key]
out[0] = v
out[1] = uint64(len(bt))
dump := append(out, bt...)
//fmt.Printf("dump %v\n", dump)
binary.Write(w, binary.LittleEndian, &dump)
}
binary.Write(w, binary.LittleEndian, &trailer)
}