diff options
Diffstat (limited to 'src/cmd/preprofile/main.go')
| -rw-r--r-- | src/cmd/preprofile/main.go | 224 |
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) - } -} |
