A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://golang.org/src/net/http/pprof/pprof.go below:

- The Go Programming Language

Source file src/net/http/pprof/pprof.go
     1  
     2  
     3  
     4  
     5  
     6  
     7  
     8  
     9  
    10  
    11  
    12  
    13  
    14  
    15  
    16  
    17  
    18  
    19  
    20  
    21  
    22  
    23  
    24  
    25  
    26  
    27  
    28  
    29  
    30  
    31  
    32  
    33  
    34  
    35  
    36  
    37  
    38  
    39  
    40  
    41  
    42  
    43  
    44  
    45  
    46  
    47  
    48  
    49  
    50  
    51  
    52  
    53  
    54  
    55  
    56  
    57  
    58  
    59  
    60  
    61  
    62  
    63  
    64  
    65  
    66  
    67  
    68  
    69  
    70  
    71  package pprof
    72  
    73  import (
    74  	"bufio"
    75  	"bytes"
    76  	"context"
    77  	"fmt"
    78  	"html"
    79  	"internal/godebug"
    80  	"internal/profile"
    81  	"io"
    82  	"log"
    83  	"net/http"
    84  	"net/url"
    85  	"os"
    86  	"runtime"
    87  	"runtime/pprof"
    88  	"runtime/trace"
    89  	"slices"
    90  	"strconv"
    91  	"strings"
    92  	"time"
    93  )
    94  
    95  func init() {
    96  	prefix := ""
    97  	if godebug.New("httpmuxgo121").Value() != "1" {
    98  		prefix = "GET "
    99  	}
   100  	http.HandleFunc(prefix+"/debug/pprof/", Index)
   101  	http.HandleFunc(prefix+"/debug/pprof/cmdline", Cmdline)
   102  	http.HandleFunc(prefix+"/debug/pprof/profile", Profile)
   103  	http.HandleFunc(prefix+"/debug/pprof/symbol", Symbol)
   104  	http.HandleFunc(prefix+"/debug/pprof/trace", Trace)
   105  }
   106  
   107  
   108  
   109  
   110  func Cmdline(w http.ResponseWriter, r *http.Request) {
   111  	w.Header().Set("X-Content-Type-Options", "nosniff")
   112  	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   113  	fmt.Fprint(w, strings.Join(os.Args, "\x00"))
   114  }
   115  
   116  func sleep(r *http.Request, d time.Duration) {
   117  	select {
   118  	case <-time.After(d):
   119  	case <-r.Context().Done():
   120  	}
   121  }
   122  
   123  func configureWriteDeadline(w http.ResponseWriter, r *http.Request, seconds float64) {
   124  	srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server)
   125  	if ok && srv.WriteTimeout > 0 {
   126  		timeout := srv.WriteTimeout + time.Duration(seconds*float64(time.Second))
   127  
   128  		rc := http.NewResponseController(w)
   129  		rc.SetWriteDeadline(time.Now().Add(timeout))
   130  	}
   131  }
   132  
   133  func serveError(w http.ResponseWriter, status int, txt string) {
   134  	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   135  	w.Header().Set("X-Go-Pprof", "1")
   136  	w.Header().Del("Content-Disposition")
   137  	w.WriteHeader(status)
   138  	fmt.Fprintln(w, txt)
   139  }
   140  
   141  
   142  
   143  
   144  func Profile(w http.ResponseWriter, r *http.Request) {
   145  	w.Header().Set("X-Content-Type-Options", "nosniff")
   146  	sec, err := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
   147  	if sec <= 0 || err != nil {
   148  		sec = 30
   149  	}
   150  
   151  	configureWriteDeadline(w, r, float64(sec))
   152  
   153  	
   154  	
   155  	w.Header().Set("Content-Type", "application/octet-stream")
   156  	w.Header().Set("Content-Disposition", `attachment; filename="profile"`)
   157  	if err := pprof.StartCPUProfile(w); err != nil {
   158  		
   159  		serveError(w, http.StatusInternalServerError,
   160  			fmt.Sprintf("Could not enable CPU profiling: %s", err))
   161  		return
   162  	}
   163  	sleep(r, time.Duration(sec)*time.Second)
   164  	pprof.StopCPUProfile()
   165  }
   166  
   167  
   168  
   169  
   170  func Trace(w http.ResponseWriter, r *http.Request) {
   171  	w.Header().Set("X-Content-Type-Options", "nosniff")
   172  	sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
   173  	if sec <= 0 || err != nil {
   174  		sec = 1
   175  	}
   176  
   177  	configureWriteDeadline(w, r, sec)
   178  
   179  	
   180  	
   181  	w.Header().Set("Content-Type", "application/octet-stream")
   182  	w.Header().Set("Content-Disposition", `attachment; filename="trace"`)
   183  	if err := trace.Start(w); err != nil {
   184  		
   185  		serveError(w, http.StatusInternalServerError,
   186  			fmt.Sprintf("Could not enable tracing: %s", err))
   187  		return
   188  	}
   189  	sleep(r, time.Duration(sec*float64(time.Second)))
   190  	trace.Stop()
   191  }
   192  
   193  
   194  
   195  
   196  func Symbol(w http.ResponseWriter, r *http.Request) {
   197  	w.Header().Set("X-Content-Type-Options", "nosniff")
   198  	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   199  
   200  	
   201  	
   202  	var buf bytes.Buffer
   203  
   204  	
   205  	
   206  	
   207  	fmt.Fprintf(&buf, "num_symbols: 1\n")
   208  
   209  	var b *bufio.Reader
   210  	if r.Method == "POST" {
   211  		b = bufio.NewReader(r.Body)
   212  	} else {
   213  		b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
   214  	}
   215  
   216  	for {
   217  		word, err := b.ReadSlice('+')
   218  		if err == nil {
   219  			word = word[0 : len(word)-1] 
   220  		}
   221  		pc, _ := strconv.ParseUint(string(word), 0, 64)
   222  		if pc != 0 {
   223  			f := runtime.FuncForPC(uintptr(pc))
   224  			if f != nil {
   225  				fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
   226  			}
   227  		}
   228  
   229  		
   230  		
   231  		if err != nil {
   232  			if err != io.EOF {
   233  				fmt.Fprintf(&buf, "reading request: %v\n", err)
   234  			}
   235  			break
   236  		}
   237  	}
   238  
   239  	w.Write(buf.Bytes())
   240  }
   241  
   242  
   243  
   244  func Handler(name string) http.Handler {
   245  	return handler(name)
   246  }
   247  
   248  type handler string
   249  
   250  func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   251  	w.Header().Set("X-Content-Type-Options", "nosniff")
   252  	p := pprof.Lookup(string(name))
   253  	if p == nil {
   254  		serveError(w, http.StatusNotFound, "Unknown profile")
   255  		return
   256  	}
   257  	if sec := r.FormValue("seconds"); sec != "" {
   258  		name.serveDeltaProfile(w, r, p, sec)
   259  		return
   260  	}
   261  	gc, _ := strconv.Atoi(r.FormValue("gc"))
   262  	if name == "heap" && gc > 0 {
   263  		runtime.GC()
   264  	}
   265  	debug, _ := strconv.Atoi(r.FormValue("debug"))
   266  	if debug != 0 {
   267  		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   268  	} else {
   269  		w.Header().Set("Content-Type", "application/octet-stream")
   270  		w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
   271  	}
   272  	p.WriteTo(w, debug)
   273  }
   274  
   275  func (name handler) serveDeltaProfile(w http.ResponseWriter, r *http.Request, p *pprof.Profile, secStr string) {
   276  	sec, err := strconv.ParseInt(secStr, 10, 64)
   277  	if err != nil || sec <= 0 {
   278  		serveError(w, http.StatusBadRequest, `invalid value for "seconds" - must be a positive integer`)
   279  		return
   280  	}
   281  	
   282  	if !profileSupportsDelta[name] {
   283  		serveError(w, http.StatusBadRequest, `"seconds" parameter is not supported for this profile type`)
   284  		return
   285  	}
   286  
   287  	configureWriteDeadline(w, r, float64(sec))
   288  
   289  	debug, _ := strconv.Atoi(r.FormValue("debug"))
   290  	if debug != 0 {
   291  		serveError(w, http.StatusBadRequest, "seconds and debug params are incompatible")
   292  		return
   293  	}
   294  	p0, err := collectProfile(p)
   295  	if err != nil {
   296  		serveError(w, http.StatusInternalServerError, "failed to collect profile")
   297  		return
   298  	}
   299  
   300  	t := time.NewTimer(time.Duration(sec) * time.Second)
   301  	defer t.Stop()
   302  
   303  	select {
   304  	case <-r.Context().Done():
   305  		err := r.Context().Err()
   306  		if err == context.DeadlineExceeded {
   307  			serveError(w, http.StatusRequestTimeout, err.Error())
   308  		} else { 
   309  			serveError(w, http.StatusInternalServerError, err.Error())
   310  		}
   311  		return
   312  	case <-t.C:
   313  	}
   314  
   315  	p1, err := collectProfile(p)
   316  	if err != nil {
   317  		serveError(w, http.StatusInternalServerError, "failed to collect profile")
   318  		return
   319  	}
   320  	ts := p1.TimeNanos
   321  	dur := p1.TimeNanos - p0.TimeNanos
   322  
   323  	p0.Scale(-1)
   324  
   325  	p1, err = profile.Merge([]*profile.Profile{p0, p1})
   326  	if err != nil {
   327  		serveError(w, http.StatusInternalServerError, "failed to compute delta")
   328  		return
   329  	}
   330  
   331  	p1.TimeNanos = ts 
   332  	p1.DurationNanos = dur
   333  
   334  	w.Header().Set("Content-Type", "application/octet-stream")
   335  	w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s-delta"`, name))
   336  	p1.Write(w)
   337  }
   338  
   339  func collectProfile(p *pprof.Profile) (*profile.Profile, error) {
   340  	var buf bytes.Buffer
   341  	if err := p.WriteTo(&buf, 0); err != nil {
   342  		return nil, err
   343  	}
   344  	ts := time.Now().UnixNano()
   345  	p0, err := profile.Parse(&buf)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  	p0.TimeNanos = ts
   350  	return p0, nil
   351  }
   352  
   353  var profileSupportsDelta = map[handler]bool{
   354  	"allocs":       true,
   355  	"block":        true,
   356  	"goroutine":    true,
   357  	"heap":         true,
   358  	"mutex":        true,
   359  	"threadcreate": true,
   360  }
   361  
   362  var profileDescriptions = map[string]string{
   363  	"allocs":       "A sampling of all past memory allocations",
   364  	"block":        "Stack traces that led to blocking on synchronization primitives",
   365  	"cmdline":      "The command line invocation of the current program",
   366  	"goroutine":    "Stack traces of all current goroutines. Use debug=2 as a query parameter to export in the same format as an unrecovered panic.",
   367  	"heap":         "A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.",
   368  	"mutex":        "Stack traces of holders of contended mutexes",
   369  	"profile":      "CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.",
   370  	"symbol":       "Maps given program counters to function names. Counters can be specified in a GET raw query or POST body, multiple counters are separated by '+'.",
   371  	"threadcreate": "Stack traces that led to the creation of new OS threads",
   372  	"trace":        "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.",
   373  }
   374  
   375  type profileEntry struct {
   376  	Name  string
   377  	Href  string
   378  	Desc  string
   379  	Count int
   380  }
   381  
   382  
   383  
   384  
   385  
   386  func Index(w http.ResponseWriter, r *http.Request) {
   387  	if name, found := strings.CutPrefix(r.URL.Path, "/debug/pprof/"); found {
   388  		if name != "" {
   389  			handler(name).ServeHTTP(w, r)
   390  			return
   391  		}
   392  	}
   393  
   394  	w.Header().Set("X-Content-Type-Options", "nosniff")
   395  	w.Header().Set("Content-Type", "text/html; charset=utf-8")
   396  
   397  	var profiles []profileEntry
   398  	for _, p := range pprof.Profiles() {
   399  		profiles = append(profiles, profileEntry{
   400  			Name:  p.Name(),
   401  			Href:  p.Name(),
   402  			Desc:  profileDescriptions[p.Name()],
   403  			Count: p.Count(),
   404  		})
   405  	}
   406  
   407  	
   408  	for _, p := range []string{"cmdline", "profile", "symbol", "trace"} {
   409  		profiles = append(profiles, profileEntry{
   410  			Name: p,
   411  			Href: p,
   412  			Desc: profileDescriptions[p],
   413  		})
   414  	}
   415  
   416  	slices.SortFunc(profiles, func(a, b profileEntry) int {
   417  		return strings.Compare(a.Name, b.Name)
   418  	})
   419  
   420  	if err := indexTmplExecute(w, profiles); err != nil {
   421  		log.Print(err)
   422  	}
   423  }
   424  
   425  func indexTmplExecute(w io.Writer, profiles []profileEntry) error {
   426  	var b bytes.Buffer
   427  	b.WriteString(`<html>
   428  <head>
   429  <title>/debug/pprof/</title>
   430  <style>
   431  .profile-name{
   432  	display:inline-block;
   433  	width:6rem;
   434  }
   435  </style>
   436  </head>
   437  <body>
   438  /debug/pprof/
   439  <br>
   440  <p>Set debug=1 as a query parameter to export in legacy text format</p>
   441  <br>
   442  Types of profiles available:
   443  <table>
   444  <thead><td>Count</td><td>Profile</td></thead>
   445  `)
   446  
   447  	for _, profile := range profiles {
   448  		link := &url.URL{Path: profile.Href, RawQuery: "debug=1"}
   449  		fmt.Fprintf(&b, "<tr><td>%d</td><td><a href='%s'>%s</a></td></tr>\n", profile.Count, link, html.EscapeString(profile.Name))
   450  	}
   451  
   452  	b.WriteString(`</table>
   453  <a href="goroutine?debug=2">full goroutine stack dump</a>
   454  <br>
   455  <p>
   456  Profile Descriptions:
   457  <ul>
   458  `)
   459  	for _, profile := range profiles {
   460  		fmt.Fprintf(&b, "<li><div class=profile-name>%s: </div> %s</li>\n", html.EscapeString(profile.Name), html.EscapeString(profile.Desc))
   461  	}
   462  	b.WriteString(`</ul>
   463  </p>
   464  </body>
   465  </html>`)
   466  
   467  	_, err := w.Write(b.Bytes())
   468  	return err
   469  }
   470  

View as plain text


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4