Skip to content

cmd/pprof: If the file under the current path contains a colon, go tool pprof will parse it into a url and will not work properly.  #63924

@cuishuang

Description

@cuishuang

What version of Go are you using (go version)?

$ go version

go version devel go1.22-6dd7462a04 Fri Oct 13 17:10:31 2023 +0000 darwin/arm64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE='on'
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/myname/Library/Caches/go-build'
GOENV='/Users/myname/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/myname/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/myname/go'
GOPRIVATE=''
GOPROXY=''
GOROOT='/Users/myname/mypath/go'
GOSUMDB='off'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/myname/mypath/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='devel go1.22-6dd7462a04 Fri Oct 13 17:10:31 2023 +0000' # I compiled it myself, it can be ignored and has nothing to do with the version.
GCCGO='gccgo'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/myname/mypath/go/src/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/9t/839s3jmj73bcgyp5x_xh3gw00000gn/T/go-build3891298911=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

I helped a colleague write a sample code to obtain the pprof file when the memory exceeds the threshold.

package main

import (
	"fmt"
	"os"
	"runtime"
	"runtime/pprof"
	"time"
)

func main() {

	ticker := time.NewTicker(10 * time.Second)

	go func() {
		for {
			time.Sleep(1e9)
			var m runtime.MemStats
			runtime.ReadMemStats(&m)

			memUsage := m.Sys / 1024 / 1024 

			if memUsage > 1024 {
				fmt.Printf("memory usage more than 1GB:%dMB\n", memUsage)

				// save pprof file
				filepath := "/xxx/yyy/path/mem" + "." + strconv.Itoa(int(time.Now().Unix()))

				f, err := os.Create(filepath)
				if err != nil {
					fmt.Println("err1:", err)
				}
				defer f.Close()

				if err2 := pprof.WriteHeapProfile(f); err2 != nil {
					fmt.Println("err2:", err2)
				}

				fmt.Println("pprof data has saved in:", filepath)

			} else {
				fmt.Printf(memory usage is%dMB\n", memUsage)
			}
		}
	}()

	for {
		select {
		case <-ticker.C:
		
			var a = make([]byte, 1073741824)
			_ = a
			fmt.Println("ticker:", time.Now())
		}
	}

	select {}

}

I tested it locally and everything was fine. He made certain modifications and then released it to the production environment. When the memory surge occurred, this program obtained the pprof file as expected, but what was confusing and surprising was that when using go tool pprof thefile, an error was reported:

Fetching profile over HTTP from http://mem_2023-11-01_14:23:16/debug/pprof/profile

profile.pprof.2023-11-03_14:23:16: Get "http://mem_2023-11-01_14:23:16/debug/pprof/profile": dial tcp: lookup mem_2023-11-01_14:23: no such host

I spent a lot of time trying to research, and one of his modifications was to change the timestamp in the file path to time.Now().Format("2006-01-02_15:04:05") in order to be more intuitive.

That is

filepath := "/xxx/yyy/path/mem" + "." + strconv.Itoa(int(time.Now().Unix())) ---> filepath := "/xxx/yyy/path /mem" + "." + time.Now().Format("2006-01-02_15:04:05")

After adding debug information several times, it was found that it was the adjustURL method in internal/driver/fetch.go. Because the file name contained a colon, url.Parse parsed the file path into a url. . .

This is confusing and counter-intuitive. After many experiments, I think we can consider determining whether there is a file with the same name in the directory. If so, treat it as a file instead of a URL.

(We only need to consider the case of executing go tool pprof in the directory where the profile is located. In the case of go tool pprof a/b/mem_pprof_file_2006_01_02_15:04:05, it will not be recognized as a URL now)

What did you expect to see?

I want to be able to use pprof normally without renaming the file

What did you see instead?

Fetching profile over HTTP from http://mem_2023-11-01_14:23:16/debug/pprof/profile

profile.pprof.2023-11-03_14:23:16: Get "http://mem_2023-11-01_14:23:16/debug/pprof/profile": dial tcp: lookup mem_2023-11-01_14:23: no such host

Metadata

Metadata

Assignees

Labels

FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions