aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/preprofile/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/preprofile/main.go')
-rw-r--r--src/cmd/preprofile/main.go224
1 files changed, 0 insertions, 224 deletions
diff --git a/src/cmd/preprofile/main.go b/src/cmd/preprofile/main.go
deleted file mode 100644
index cf747266ca..0000000000
--- a/src/cmd/preprofile/main.go
+++ /dev/null
@@ -1,224 +0,0 @@
-// 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.
-
-// Preprofile handles pprof files.
-//
-// Usage:
-//
-// go tool preprofile [-v] [-o output] [-i (pprof)input]
-//
-//
-
-package main
-
-import (
- "bufio"
- "flag"
- "fmt"
- "internal/profile"
- "log"
- "os"
- "path/filepath"
- "strconv"
-)
-
-// The current Go Compiler consumes significantly long compilation time when the PGO
-// is enabled. To optimize the existing flow and reduce build time of multiple Go
-// services, we create a standalone tool, PGO preprocessor, to extract information
-// from collected profiling files and to cache the WeightedCallGraph in one time
-// fashion. By adding the new tool to the Go compiler, it will reduce the time
-// of repeated profiling file parsing and avoid WeightedCallGraph reconstruction
-// in current Go Compiler.
-// The format of the pre-processed output is as follows.
-//
-// Header
-// caller_name
-// callee_name
-// "call site offset" "caller's start line number" "flat" "cum" "call edge weight"
-// ...
-// caller_name
-// callee_name
-// "call site offset" "caller's start line number" "flat" "cum" "call edge weight"
-
-func usage() {
- fmt.Fprintf(os.Stderr, "MUST have (pprof) input file \n")
- fmt.Fprintf(os.Stderr, "usage: go tool preprofile [-v] [-o output] [-i (pprof)input] \n\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-type NodeMapKey struct {
- CallerName string
- CalleeName string
- CallSiteOffset int // Line offset from function start line.
- CallStartLine int // Start line of the function. Can be 0 which means missing.
-}
-
-type Weights struct {
- NFlat int64
- NCum int64
- EWeight int64
-}
-
-func readPprofFile(profileFile string, outputFile string, verbose bool) bool {
- // open the pprof profile file
- f, err := os.Open(profileFile)
- if err != nil {
- log.Fatal("failed to open file " + profileFile)
- return false
- }
- defer f.Close()
- p, err := profile.Parse(f)
- if err != nil {
- log.Fatal("failed to Parse profile file.")
- return false
- }
-
- if len(p.Sample) == 0 {
- // We accept empty profiles, but there is nothing to do.
- return false
- }
-
- valueIndex := -1
- for i, s := range p.SampleType {
- // Samples count is the raw data collected, and CPU nanoseconds is just
- // a scaled version of it, so either one we can find is fine.
- if (s.Type == "samples" && s.Unit == "count") ||
- (s.Type == "cpu" && s.Unit == "nanoseconds") {
- valueIndex = i
- break
- }
- }
-
- if valueIndex == -1 {
- log.Fatal("failed to find CPU samples count or CPU nanoseconds value-types in profile.")
- return false
- }
-
- // The processing here is equivalent to cmd/compile/internal/pgo.createNamedEdgeMap.
- g := profile.NewGraph(p, &profile.Options{
- SampleValue: func(v []int64) int64 { return v[valueIndex] },
- })
-
- nFlat := make(map[string]int64)
- nCum := make(map[string]int64)
-
- // Accummulate weights for the same node.
- for _, n := range g.Nodes {
- canonicalName := n.Info.Name
- nFlat[canonicalName] += n.FlatValue()
- nCum[canonicalName] += n.CumValue()
- }
-
- TotalNodeWeight := int64(0)
- TotalEdgeWeight := int64(0)
-
- NodeMap := make(map[NodeMapKey]*Weights)
- NodeWeightMap := make(map[string]int64)
-
- for _, n := range g.Nodes {
- TotalNodeWeight += n.FlatValue()
- canonicalName := n.Info.Name
- // Create the key to the nodeMapKey.
- nodeinfo := NodeMapKey{
- CallerName: canonicalName,
- CallSiteOffset: n.Info.Lineno - n.Info.StartLine,
- CallStartLine: n.Info.StartLine,
- }
-
- if nodeinfo.CallStartLine == 0 {
- if verbose {
- log.Println("[PGO] warning: " + canonicalName + " relative line number is missing from the profile")
- }
- }
-
- for _, e := range n.Out {
- TotalEdgeWeight += e.WeightValue()
- nodeinfo.CalleeName = e.Dest.Info.Name
- if w, ok := NodeMap[nodeinfo]; ok {
- w.EWeight += e.WeightValue()
- } else {
- weights := new(Weights)
- weights.NFlat = nFlat[canonicalName]
- weights.NCum = nCum[canonicalName]
- weights.EWeight = e.WeightValue()
- NodeMap[nodeinfo] = weights
- }
- }
- }
-
- for _, n := range g.Nodes {
- lineno := fmt.Sprintf("%v", n.Info.Lineno)
- canonicalName := n.Info.Name + "-" + lineno
- if _, ok := (NodeWeightMap)[canonicalName]; ok {
- (NodeWeightMap)[canonicalName] += n.CumValue()
- } else {
- (NodeWeightMap)[canonicalName] = n.CumValue()
- }
- }
-
- var fNodeMap *os.File
- if outputFile == "" {
- fNodeMap = os.Stdout
- } else {
- dirPath := filepath.Dir(outputFile)
- _, err := os.Stat(dirPath)
- if err != nil {
- log.Fatal("Directory does not exist: ", dirPath)
- }
- base := filepath.Base(outputFile)
- outputFile = filepath.Join(dirPath, base)
-
- // write out NodeMap to a file
- fNodeMap, err = os.Create(outputFile)
- if err != nil {
- log.Fatal("Error creating output file:", err)
- return false
- }
-
- defer fNodeMap.Close() // Close the file when done writing
- }
-
- w := bufio.NewWriter(fNodeMap)
- w.WriteString("GO PREPROFILE V1\n")
- count := 1
- separator := " "
- for key, element := range NodeMap {
- line := key.CallerName + "\n"
- w.WriteString(line)
- line = key.CalleeName + "\n"
- w.WriteString(line)
- line = strconv.Itoa(key.CallSiteOffset)
- line = line + separator + strconv.Itoa(key.CallStartLine)
- line = line + separator + strconv.FormatInt(element.NFlat, 10)
- line = line + separator + strconv.FormatInt(element.NCum, 10)
- line = line + separator + strconv.FormatInt(element.EWeight, 10) + "\n"
- w.WriteString(line)
- w.Flush()
- count += 1
- }
-
- if TotalNodeWeight == 0 || TotalEdgeWeight == 0 {
- return false
- }
-
- return true
-}
-
-var dumpCode = flag.String("o", "", "dump output file ")
-var input = flag.String("i", "", "input pprof file ")
-var verbose = flag.Bool("v", false, "verbose log")
-
-func main() {
- log.SetFlags(0)
- log.SetPrefix("preprofile: ")
-
- flag.Usage = usage
- flag.Parse()
- if *input == "" {
- usage()
- } else {
- readPprofFile(*input, *dumpCode, *verbose)
- }
-}