import (
"cmd/internal/browser"
"cmd/internal/telemetry/counter"
+ "cmp"
"flag"
"fmt"
"internal/trace"
+ "internal/trace/event"
"internal/trace/raw"
"internal/trace/traceviewer"
"io"
"net/http"
_ "net/http/pprof" // Required to use pprof
"os"
+ "slices"
"sync/atomic"
+ "text/tabwriter"
"time"
)
Flags:
-http=addr: HTTP service address (e.g., ':6060')
-pprof=type: print a pprof-like profile instead
- -d=int: print debug info such as parsed events (1 for high-level, 2 for low-level)
+ -d=mode: print debug info and exit (modes: wire, parsed, footprint)
Note that while the various profiles available when launching
'go tool trace' work on every browser, the trace viewer itself
var (
httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
- debugFlag = flag.Int("d", 0, "print debug information (1 for basic debug info, 2 for lower-level info)")
+ debugFlag = flag.String("d", "", "print debug info and exit (modes: wire, parsed, footprint)")
// The binary file name, left here for serveSVGProfile.
programBinary string
}
// Debug flags.
- switch *debugFlag {
- case 1:
- logAndDie(debugProcessedEvents(tracef))
- case 2:
- logAndDie(debugRawEvents(tracef))
+ if *debugFlag != "" {
+ switch *debugFlag {
+ case "parsed":
+ logAndDie(debugProcessedEvents(tracef))
+ case "wire":
+ logAndDie(debugRawEvents(tracef))
+ case "footprint":
+ logAndDie(debugEventsFootprint(tracef))
+ default:
+ logAndDie(fmt.Errorf("invalid debug mode %s, want one of: parsed, wire, footprint", *debugFlag))
+ }
}
ln, err := net.Listen("tcp", *httpFlag)
}
}
+func debugEventsFootprint(trc io.Reader) error {
+ cr := countingReader{r: trc}
+ tr, err := raw.NewReader(&cr)
+ if err != nil {
+ return err
+ }
+ type eventStats struct {
+ typ event.Type
+ count int
+ bytes int
+ }
+ var stats [256]eventStats
+ for i := range stats {
+ stats[i].typ = event.Type(i)
+ }
+ eventsRead := 0
+ for {
+ e, err := tr.ReadEvent()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ s := &stats[e.Ev]
+ s.count++
+ s.bytes += e.EncodedSize()
+ eventsRead++
+ }
+ slices.SortFunc(stats[:], func(a, b eventStats) int {
+ return cmp.Compare(b.bytes, a.bytes)
+ })
+ specs := tr.Version().Specs()
+ w := tabwriter.NewWriter(os.Stdout, 3, 8, 2, ' ', 0)
+ fmt.Fprintf(w, "Event\tBytes\t%%\tCount\t%%\n")
+ fmt.Fprintf(w, "-\t-\t-\t-\t-\n")
+ for i := range stats {
+ stat := &stats[i]
+ name := ""
+ if int(stat.typ) >= len(specs) {
+ name = fmt.Sprintf("<unknown (%d)>", stat.typ)
+ } else {
+ name = specs[stat.typ].Name
+ }
+ bytesPct := float64(stat.bytes) / float64(cr.bytesRead.Load()) * 100
+ countPct := float64(stat.count) / float64(eventsRead) * 100
+ fmt.Fprintf(w, "%s\t%d\t%.2f%%\t%d\t%.2f%%\n", name, stat.bytes, bytesPct, stat.count, countPct)
+ }
+ w.Flush()
+ return nil
+}
+
type countingReader struct {
r io.Reader
bytesRead atomic.Int64
package raw
import (
+ "encoding/binary"
"strconv"
"strings"
}
return s.String()
}
+
+// EncodedSize returns the canonical encoded size of an event.
+func (e *Event) EncodedSize() int {
+ size := 1
+ var buf [binary.MaxVarintLen64]byte
+ for _, arg := range e.Args {
+ size += binary.PutUvarint(buf[:], arg)
+ }
+ spec := e.Version.Specs()[e.Ev]
+ if spec.HasData {
+ size += binary.PutUvarint(buf[:], uint64(len(e.Data)))
+ size += len(e.Data)
+ }
+ return size
+}
+++ /dev/null
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "cmp"
- "encoding/binary"
- "flag"
- "fmt"
- "io"
- "log"
- "os"
- "slices"
- "text/tabwriter"
-
- "internal/trace/event"
- "internal/trace/raw"
-)
-
-func init() {
- flag.Usage = func() {
- fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [mode]\n", os.Args[0])
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "Accepts a trace at stdin.\n")
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "Supported modes:")
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "* size - dumps size stats\n")
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- flag.PrintDefaults()
- }
- log.SetFlags(0)
-}
-
-func main() {
- log.SetPrefix("")
- flag.Parse()
-
- if flag.NArg() != 1 {
- log.Print("missing mode argument")
- flag.Usage()
- os.Exit(1)
- }
- var err error
- switch mode := flag.Arg(0); mode {
- case "size":
- err = printSizeStats(os.Stdin)
- default:
- log.Printf("unknown mode %q", mode)
- flag.Usage()
- os.Exit(1)
- }
- if err != nil {
- log.Fatalf("error: %v", err)
- os.Exit(1)
- }
-}
-
-func printSizeStats(r io.Reader) error {
- cr := countingReader{Reader: r}
- tr, err := raw.NewReader(&cr)
- if err != nil {
- return err
- }
- type eventStats struct {
- typ event.Type
- count int
- bytes int
- }
- var stats [256]eventStats
- for i := range stats {
- stats[i].typ = event.Type(i)
- }
- eventsRead := 0
- for {
- e, err := tr.ReadEvent()
- if err == io.EOF {
- break
- }
- if err != nil {
- return err
- }
- s := &stats[e.Ev]
- s.count++
- s.bytes += encodedSize(&e)
- eventsRead++
- }
- slices.SortFunc(stats[:], func(a, b eventStats) int {
- return cmp.Compare(b.bytes, a.bytes)
- })
- specs := tr.Version().Specs()
- w := tabwriter.NewWriter(os.Stdout, 3, 8, 2, ' ', 0)
- fmt.Fprintf(w, "Event\tBytes\t%%\tCount\t%%\n")
- fmt.Fprintf(w, "-\t-\t-\t-\t-\n")
- for i := range stats {
- stat := &stats[i]
- name := ""
- if int(stat.typ) >= len(specs) {
- name = fmt.Sprintf("<unknown (%d)>", stat.typ)
- } else {
- name = specs[stat.typ].Name
- }
- bytesPct := float64(stat.bytes) / float64(cr.bytesRead) * 100
- countPct := float64(stat.count) / float64(eventsRead) * 100
- fmt.Fprintf(w, "%s\t%d\t%.2f%%\t%d\t%.2f%%\n", name, stat.bytes, bytesPct, stat.count, countPct)
- }
- w.Flush()
- return nil
-}
-
-func encodedSize(e *raw.Event) int {
- size := 1
- var buf [binary.MaxVarintLen64]byte
- for _, arg := range e.Args {
- size += binary.PutUvarint(buf[:], arg)
- }
- spec := e.Version.Specs()[e.Ev]
- if spec.HasData {
- size += binary.PutUvarint(buf[:], uint64(len(e.Data)))
- size += len(e.Data)
- }
- return size
-}
-
-type countingReader struct {
- io.Reader
- bytesRead int
-}
-
-func (r *countingReader) Read(b []byte) (int, error) {
- n, err := r.Reader.Read(b)
- r.bytesRead += n
- return n, err
-}
+++ /dev/null
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "log"
- "os"
-
- "internal/trace/raw"
- "internal/trace/version"
-)
-
-func init() {
- flag.Usage = func() {
- fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [mode]\n", os.Args[0])
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "Supported modes:")
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "* text2bytes - converts a text format trace to bytes\n")
- fmt.Fprintf(flag.CommandLine.Output(), "* bytes2text - converts a byte format trace to text\n")
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- flag.PrintDefaults()
- }
- log.SetFlags(0)
-}
-
-func main() {
- flag.Parse()
- if narg := flag.NArg(); narg != 1 {
- log.Fatal("expected exactly one positional argument: the mode to operate in; see -h output")
- }
-
- r := os.Stdin
- w := os.Stdout
-
- var tr traceReader
- var tw traceWriter
- var err error
-
- switch flag.Arg(0) {
- case "text2bytes":
- tr, err = raw.NewTextReader(r)
- if err != nil {
- log.Fatal(err)
- }
- tw, err = raw.NewWriter(w, tr.Version())
- if err != nil {
- log.Fatal(err)
- }
- case "bytes2text":
- tr, err = raw.NewReader(r)
- if err != nil {
- log.Fatal(err)
- }
- tw, err = raw.NewTextWriter(w, tr.Version())
- if err != nil {
- log.Fatal(err)
- }
- }
- for {
- ev, err := tr.ReadEvent()
- if err == io.EOF {
- break
- }
- if err != nil {
- log.Fatal(err)
- }
- if err := tw.WriteEvent(ev); err != nil {
- log.Fatal(err)
- }
- }
-}
-
-type traceReader interface {
- Version() version.Version
- ReadEvent() (raw.Event, error)
-}
-
-type traceWriter interface {
- WriteEvent(raw.Event) error
-}
+++ /dev/null
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "log"
- "os"
-
- "internal/trace"
- "internal/trace/testtrace"
-)
-
-func init() {
- flag.Usage = func() {
- fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s\n", os.Args[0])
- fmt.Fprintf(flag.CommandLine.Output(), "\n")
- fmt.Fprintf(flag.CommandLine.Output(), "Accepts a trace at stdin and validates it.\n")
- flag.PrintDefaults()
- }
- log.SetFlags(0)
-}
-
-var logEvents = flag.Bool("log-events", false, "whether to log events")
-
-func main() {
- flag.Parse()
-
- r, err := trace.NewReader(os.Stdin)
- if err != nil {
- log.Fatal(err)
- }
- v := testtrace.NewValidator()
- for {
- ev, err := r.ReadEvent()
- if err == io.EOF {
- break
- }
- if err != nil {
- log.Fatal(err)
- }
- if *logEvents {
- log.Println(ev.String())
- }
- if err := v.Event(ev); err != nil {
- log.Fatal(err)
- }
- }
-}