Go command to translate #K/oprofile to pprof format.
authorRonald G. Minnich <rminnich@google.com>
Thu, 29 May 2014 15:02:53 +0000 (08:02 -0700)
committerRonald G. Minnich <rminnich@google.com>
Thu, 29 May 2014 15:02:53 +0000 (08:02 -0700)
This works. Turns out addr2line is a piece of @@@@, which means that
we're still not seeing symbol names in go tool pprof. One problem at a
time.

Note that when we move to using ticks, not ns, for kpoprofile, this
will have to change too.

tools/profile/op2.go [new file with mode: 0644]

diff --git a/tools/profile/op2.go b/tools/profile/op2.go
new file mode 100644 (file)
index 0000000..c96bd0d
--- /dev/null
@@ -0,0 +1,107 @@
+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)
+
+}