Source file src/cmd/preprofile/main.go

     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  package main
    13  
    14  import (
    15  	"bufio"
    16  	"cmd/internal/objabi"
    17  	"cmd/internal/pgo"
    18  	"cmd/internal/telemetry/counter"
    19  	"flag"
    20  	"fmt"
    21  	"log"
    22  	"os"
    23  )
    24  
    25  func usage() {
    26  	fmt.Fprintf(os.Stderr, "usage: go tool preprofile [-v] [-o output] -i input\n\n")
    27  	flag.PrintDefaults()
    28  	os.Exit(2)
    29  }
    30  
    31  var (
    32  	output = flag.String("o", "", "output file path")
    33  	input  = flag.String("i", "", "input pprof file path")
    34  )
    35  
    36  func preprocess(profileFile string, outputFile string) error {
    37  	f, err := os.Open(profileFile)
    38  	if err != nil {
    39  		return fmt.Errorf("error opening profile: %w", err)
    40  	}
    41  	defer f.Close()
    42  
    43  	r := bufio.NewReader(f)
    44  	d, err := pgo.FromPProf(r)
    45  	if err != nil {
    46  		return fmt.Errorf("error parsing profile: %w", err)
    47  	}
    48  
    49  	var out *os.File
    50  	if outputFile == "" {
    51  		out = os.Stdout
    52  	} else {
    53  		out, err = os.Create(outputFile)
    54  		if err != nil {
    55  			return fmt.Errorf("error creating output file: %w", err)
    56  		}
    57  		defer out.Close()
    58  	}
    59  
    60  	w := bufio.NewWriter(out)
    61  	if _, err := d.WriteTo(w); err != nil {
    62  		return fmt.Errorf("error writing output file: %w", err)
    63  	}
    64  
    65  	return nil
    66  }
    67  
    68  func main() {
    69  	objabi.AddVersionFlag()
    70  
    71  	log.SetFlags(0)
    72  	log.SetPrefix("preprofile: ")
    73  	counter.Open()
    74  
    75  	flag.Usage = usage
    76  	flag.Parse()
    77  	counter.Inc("preprofile/invocations")
    78  	counter.CountFlags("preprofile/flag:", *flag.CommandLine)
    79  	if *input == "" {
    80  		log.Print("Input pprof path required (-i)")
    81  		usage()
    82  	}
    83  
    84  	if err := preprocess(*input, *output); err != nil {
    85  		log.Fatal(err)
    86  	}
    87  }
    88  

View as plain text