1
2
3
4
5 package main
6
7 import (
8 "cmp"
9 "encoding/binary"
10 "flag"
11 "fmt"
12 "io"
13 "log"
14 "os"
15 "slices"
16 "text/tabwriter"
17
18 "internal/trace/event"
19 "internal/trace/raw"
20 )
21
22 func init() {
23 flag.Usage = func() {
24 fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [mode]\n", os.Args[0])
25 fmt.Fprintf(flag.CommandLine.Output(), "\n")
26 fmt.Fprintf(flag.CommandLine.Output(), "Accepts a trace at stdin.\n")
27 fmt.Fprintf(flag.CommandLine.Output(), "\n")
28 fmt.Fprintf(flag.CommandLine.Output(), "Supported modes:")
29 fmt.Fprintf(flag.CommandLine.Output(), "\n")
30 fmt.Fprintf(flag.CommandLine.Output(), "* size - dumps size stats\n")
31 fmt.Fprintf(flag.CommandLine.Output(), "\n")
32 flag.PrintDefaults()
33 }
34 log.SetFlags(0)
35 }
36
37 func main() {
38 log.SetPrefix("")
39 flag.Parse()
40
41 if flag.NArg() != 1 {
42 log.Print("missing mode argument")
43 flag.Usage()
44 os.Exit(1)
45 }
46 var err error
47 switch mode := flag.Arg(0); mode {
48 case "size":
49 err = printSizeStats(os.Stdin)
50 default:
51 log.Printf("unknown mode %q", mode)
52 flag.Usage()
53 os.Exit(1)
54 }
55 if err != nil {
56 log.Fatalf("error: %v", err)
57 os.Exit(1)
58 }
59 }
60
61 func printSizeStats(r io.Reader) error {
62 cr := countingReader{Reader: r}
63 tr, err := raw.NewReader(&cr)
64 if err != nil {
65 return err
66 }
67 type eventStats struct {
68 typ event.Type
69 count int
70 bytes int
71 }
72 var stats [256]eventStats
73 for i := range stats {
74 stats[i].typ = event.Type(i)
75 }
76 eventsRead := 0
77 for {
78 e, err := tr.ReadEvent()
79 if err == io.EOF {
80 break
81 }
82 if err != nil {
83 return err
84 }
85 s := &stats[e.Ev]
86 s.count++
87 s.bytes += encodedSize(&e)
88 eventsRead++
89 }
90 slices.SortFunc(stats[:], func(a, b eventStats) int {
91 return cmp.Compare(b.bytes, a.bytes)
92 })
93 specs := tr.Version().Specs()
94 w := tabwriter.NewWriter(os.Stdout, 3, 8, 2, ' ', 0)
95 fmt.Fprintf(w, "Event\tBytes\t%%\tCount\t%%\n")
96 fmt.Fprintf(w, "-\t-\t-\t-\t-\n")
97 for i := range stats {
98 stat := &stats[i]
99 name := ""
100 if int(stat.typ) >= len(specs) {
101 name = fmt.Sprintf("<unknown (%d)>", stat.typ)
102 } else {
103 name = specs[stat.typ].Name
104 }
105 bytesPct := float64(stat.bytes) / float64(cr.bytesRead) * 100
106 countPct := float64(stat.count) / float64(eventsRead) * 100
107 fmt.Fprintf(w, "%s\t%d\t%.2f%%\t%d\t%.2f%%\n", name, stat.bytes, bytesPct, stat.count, countPct)
108 }
109 w.Flush()
110 return nil
111 }
112
113 func encodedSize(e *raw.Event) int {
114 size := 1
115 var buf [binary.MaxVarintLen64]byte
116 for _, arg := range e.Args {
117 size += binary.PutUvarint(buf[:], arg)
118 }
119 spec := e.Version.Specs()[e.Ev]
120 if spec.HasData {
121 size += binary.PutUvarint(buf[:], uint64(len(e.Data)))
122 size += len(e.Data)
123 }
124 return size
125 }
126
127 type countingReader struct {
128 io.Reader
129 bytesRead int
130 }
131
132 func (r *countingReader) Read(b []byte) (int, error) {
133 n, err := r.Reader.Read(b)
134 r.bytesRead += n
135 return n, err
136 }
137
View as plain text