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  //
    13  //
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"cmd/internal/objabi"
    20  	"cmd/internal/pgo"
    21  	"cmd/internal/telemetry"
    22  	"flag"
    23  	"fmt"
    24  	"log"
    25  	"os"
    26  )
    27  
    28  func 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  
    34  var (
    35  	output = flag.String("o", "", "output file path")
    36  	input  = flag.String("i", "", "input pprof file path")
    37  )
    38  
    39  func 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  
    71  func main() {
    72  	objabi.AddVersionFlag()
    73  
    74  	log.SetFlags(0)
    75  	log.SetPrefix("preprofile: ")
    76  	telemetry.Start()
    77  
    78  	flag.Usage = usage
    79  	flag.Parse()
    80  	telemetry.Inc("preprofile/invocations")
    81  	telemetry.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  

View as plain text