1// Copyright 2023 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Preprofile creates an intermediate representation of a pprof profile for use 6// during PGO in the compiler. This transformation depends only on the profile 7// itself and is thus wasteful to perform in every invocation of the compiler. 8// 9// Usage: 10// 11// go tool preprofile [-v] [-o output] -i input 12// 13// 14 15package main 16 17import ( 18 "bufio" 19 "cmd/internal/objabi" 20 "cmd/internal/pgo" 21 "cmd/internal/telemetry/counter" 22 "flag" 23 "fmt" 24 "log" 25 "os" 26) 27 28func usage() { 29 fmt.Fprintf(os.Stderr, "usage: go tool preprofile [-v] [-o output] -i input\n\n") 30 flag.PrintDefaults() 31 os.Exit(2) 32} 33 34var ( 35 output = flag.String("o", "", "output file path") 36 input = flag.String("i", "", "input pprof file path") 37) 38 39func preprocess(profileFile string, outputFile string) error { 40 f, err := os.Open(profileFile) 41 if err != nil { 42 return fmt.Errorf("error opening profile: %w", err) 43 } 44 defer f.Close() 45 46 r := bufio.NewReader(f) 47 d, err := pgo.FromPProf(r) 48 if err != nil { 49 return fmt.Errorf("error parsing profile: %w", err) 50 } 51 52 var out *os.File 53 if outputFile == "" { 54 out = os.Stdout 55 } else { 56 out, err = os.Create(outputFile) 57 if err != nil { 58 return fmt.Errorf("error creating output file: %w", err) 59 } 60 defer out.Close() 61 } 62 63 w := bufio.NewWriter(out) 64 if _, err := d.WriteTo(w); err != nil { 65 return fmt.Errorf("error writing output file: %w", err) 66 } 67 68 return nil 69} 70 71func main() { 72 objabi.AddVersionFlag() 73 74 log.SetFlags(0) 75 log.SetPrefix("preprofile: ") 76 counter.Open() 77 78 flag.Usage = usage 79 flag.Parse() 80 counter.Inc("preprofile/invocations") 81 counter.CountFlags("preprofile/flag:", *flag.CommandLine) 82 if *input == "" { 83 log.Print("Input pprof path required (-i)") 84 usage() 85 } 86 87 if err := preprocess(*input, *output); err != nil { 88 log.Fatal(err) 89 } 90} 91