Move Linux perf format conversion into perf tool, drop kprof2perf
[akaros.git] / tools / profile / op2.go
1 package main
2
3 import (
4         "encoding/binary"
5         "fmt"
6         "io"
7         "os"
8 )
9
10 /*
11 first word
12 high 8 bits is ee, which is an invalid address on amd64. 
13 next 8 bits is protocol version
14 next 16 bits is unused, MBZ. Later, we can make it a packet type. 
15 next 16 bits is core id
16 next 8 bits is unused
17 next 8 bits is # words following.
18
19 second word is time in ns. (soon to be tsc ticks)
20
21 Third and following words are PCs, there must be at least one of them. 
22  */
23 type sample struct {
24         Wordcount,_ uint8
25         Coreid uint16
26         _ uint16
27         Version, Marker uint8
28         Ns uint64
29 }
30
31 type backtrace struct {
32         Pcs []uint64
33 }
34
35 /* the docs lie. Perl expects Count to be zero. I only wasted a day figuring this out. */
36 type hdr struct {
37         Count, Slots, Format, Period, Padding uint64
38 }
39
40 type record struct {
41         Count, Size uint64
42         Pcs []uint64
43 }
44
45 type trailer struct {
46         Zero, One, Zeroh uint64
47 }
48
49 func main() {
50         var s sample
51         
52         r := io.Reader(os.Stdin)
53         w := io.Writer(os.Stdout)
54
55         records := make(map[string]uint64, 16384)
56         backtraces := make(map[string][]uint64,1024)
57
58         /* ignore the documentation, it's wrong, first word must be zero.
59          * the perl code that figures word length depends on it.
60          */
61         hdr := hdr{0,3,0,10000,0}
62         trailer := trailer{0,1,0}
63         start := uint64(0)
64         end := start
65         nsamples := end
66         for binary.Read(r, binary.LittleEndian, &s) == nil {
67                 numpcs := int(s.Wordcount)
68                 bt := make([]uint64, numpcs)
69                 binary.Read(r, binary.LittleEndian, &bt)
70                 //fmt.Printf("%v\n", bt)
71                 record := ""
72                 /* Fix the symbols. pprof was unhappy about the 0xfffffff.
73                  * N.B. The fact that we have to mess with the bt values
74                  * is the reason we did not write a stringer for bt.
75                  */
76                 for i := range(bt) {
77                         bt[i] = bt[i] & ((uint64(1)<<32)-1)
78                         record = record + fmt.Sprintf("0x%x ",bt[i])
79                 }
80                 records[record]++
81                 backtraces[record] = bt
82                 //fmt.Printf("%v %d %d %x %v record %v\n", s, s.Wordcount, s.Coreid, s.Ns, bt, record)
83                 /* how sad, once we go to ticks this gets ugly. */
84                 if start == 0 {
85                         start = s.Ns
86                 }
87                 end = s.Ns
88                 nsamples ++
89         }
90         /* we'll need to fix this once we go to ticks. */
91         hdr.Period = (end - start) / nsamples
92         hdr.Count = uint64(0) // !@$@!#$!@#$len(records))
93         //fmt.Printf("start %v end %v nsamples %d period %d\n", start, end, nsamples, hdr.Period)
94         binary.Write(w, binary.LittleEndian, &hdr)
95         out := make([]uint64, 2)
96         /* note that the backtrace length varies. But we're good with that. */
97         for key, v := range(records) {
98                 bt := backtraces[key]
99                 out[0] = v
100                 out[1] = uint64(len(bt))
101                 dump := append(out, bt...)
102                 //fmt.Printf("dump %v\n", dump)
103                 binary.Write(w, binary.LittleEndian, &dump)
104         }
105         binary.Write(w, binary.LittleEndian, &trailer)
106
107 }