...

Source file src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go

     1	// Copyright 2017 Google Inc. All Rights Reserved.
     2	//
     3	// Licensed under the Apache License, Version 2.0 (the "License");
     4	// you may not use this file except in compliance with the License.
     5	// You may obtain a copy of the License at
     6	//
     7	//     http://www.apache.org/licenses/LICENSE-2.0
     8	//
     9	// Unless required by applicable law or agreed to in writing, software
    10	// distributed under the License is distributed on an "AS IS" BASIS,
    11	// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12	// See the License for the specific language governing permissions and
    13	// limitations under the License.
    14	
    15	package driver
    16	
    17	import (
    18		"encoding/json"
    19		"html/template"
    20		"net/http"
    21		"strings"
    22	
    23		"github.com/google/pprof/internal/graph"
    24		"github.com/google/pprof/internal/measurement"
    25		"github.com/google/pprof/internal/report"
    26	)
    27	
    28	type treeNode struct {
    29		Name      string      `json:"n"`
    30		FullName  string      `json:"f"`
    31		Cum       int64       `json:"v"`
    32		CumFormat string      `json:"l"`
    33		Percent   string      `json:"p"`
    34		Children  []*treeNode `json:"c"`
    35	}
    36	
    37	// flamegraph generates a web page containing a flamegraph.
    38	func (ui *webInterface) flamegraph(w http.ResponseWriter, req *http.Request) {
    39		// Force the call tree so that the graph is a tree.
    40		// Also do not trim the tree so that the flame graph contains all functions.
    41		rpt, errList := ui.makeReport(w, req, []string{"svg"}, "call_tree", "true", "trim", "false")
    42		if rpt == nil {
    43			return // error already reported
    44		}
    45	
    46		// Generate dot graph.
    47		g, config := report.GetDOT(rpt)
    48		var nodes []*treeNode
    49		nroots := 0
    50		rootValue := int64(0)
    51		nodeArr := []string{}
    52		nodeMap := map[*graph.Node]*treeNode{}
    53		// Make all nodes and the map, collect the roots.
    54		for _, n := range g.Nodes {
    55			v := n.CumValue()
    56			fullName := n.Info.PrintableName()
    57			node := &treeNode{
    58				Name:      graph.ShortenFunctionName(fullName),
    59				FullName:  fullName,
    60				Cum:       v,
    61				CumFormat: config.FormatValue(v),
    62				Percent:   strings.TrimSpace(measurement.Percentage(v, config.Total)),
    63			}
    64			nodes = append(nodes, node)
    65			if len(n.In) == 0 {
    66				nodes[nroots], nodes[len(nodes)-1] = nodes[len(nodes)-1], nodes[nroots]
    67				nroots++
    68				rootValue += v
    69			}
    70			nodeMap[n] = node
    71			// Get all node names into an array.
    72			nodeArr = append(nodeArr, n.Info.Name)
    73		}
    74		// Populate the child links.
    75		for _, n := range g.Nodes {
    76			node := nodeMap[n]
    77			for child := range n.Out {
    78				node.Children = append(node.Children, nodeMap[child])
    79			}
    80		}
    81	
    82		rootNode := &treeNode{
    83			Name:      "root",
    84			FullName:  "root",
    85			Cum:       rootValue,
    86			CumFormat: config.FormatValue(rootValue),
    87			Percent:   strings.TrimSpace(measurement.Percentage(rootValue, config.Total)),
    88			Children:  nodes[0:nroots],
    89		}
    90	
    91		// JSON marshalling flame graph
    92		b, err := json.Marshal(rootNode)
    93		if err != nil {
    94			http.Error(w, "error serializing flame graph", http.StatusInternalServerError)
    95			ui.options.UI.PrintErr(err)
    96			return
    97		}
    98	
    99		ui.render(w, "flamegraph", rpt, errList, config.Labels, webArgs{
   100			FlameGraph: template.JS(b),
   101			Nodes:      nodeArr,
   102		})
   103	}
   104	

View as plain text