Source File
legacy_profile.go
Belonging Package
github.com/google/pprof/profile
package profile
import (
)
var (
countStartRE = regexp.MustCompile(`\A(\S+) profile: total \d+\z`)
countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\z`)
heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz?`)
fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz?`)
threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
spaceDigits = `\s+[[:digit:]]+`
hexPair = `\s+[[:xdigit:]]+:[[:xdigit:]]+`
cHex = `(?:0x)?([[:xdigit:]]+)`
cHexRange = `\s*` + cHex + `[\s-]?` + oSpace + cHex + `:?`
cSpaceString = `(?:\s+(\S+))?`
cSpaceHex = `(?:\s+([[:xdigit:]]+))?`
cSpaceAtOffset = `(?:\s+\(@([[:xdigit:]]+)\))?`
cPerm = `(?:\s+([-rwxp]+))?`
procMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceHex + hexPair + spaceDigits + cSpaceString)
briefMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceString + cSpaceAtOffset + cSpaceHex)
for .Scan() && isSpaceOrComment(.Text()) {
}
if := .Err(); != nil {
return nil,
}
:= countStartRE.FindStringSubmatch(.Text())
if == nil {
return nil, errUnrecognized
}
:= [1]
:= &Profile{
PeriodType: &ValueType{Type: , Unit: "count"},
Period: 1,
SampleType: []*ValueType{{Type: , Unit: "count"}},
}
:= make(map[uint64]*Location)
for .Scan() {
:= .Text()
if isSpaceOrComment() {
continue
}
if strings.HasPrefix(, "---") {
break
}
:= countRE.FindStringSubmatch()
if == nil {
return nil, errMalformed
}
, := strconv.ParseInt([1], 0, 64)
if != nil {
return nil, errMalformed
}
:= strings.Fields([2])
:= make([]*Location, 0, len())
for , := range {
, := strconv.ParseUint(, 0, 64)
if != nil {
return nil, errMalformed
func ( *Profile) () {
:= make(map[*Location]bool, len(.Location))
var []*Location
for , := range .Sample {
for , := range .Location {
if [] {
continue
}
.ID = uint64(len() + 1)
= append(, )
[] = true
}
}
.Location =
}
func ( *Profile) () {
:= make(map[*Function]bool, len(.Function))
var []*Function
for , := range .Location {
for , := range .Line {
:= .Function
if == nil || [] {
continue
}
.ID = uint64(len() + 1)
= append(, )
[] = true
}
}
.Function =
}
for , := range .Mapping {
.ID = uint64( + 1)
}
}
var cpuInts = []func([]byte) (uint64, []byte){
get32l,
get32b,
get64l,
get64b,
}
func ( []byte) (uint64, []byte) {
if len() < 4 {
return 0, nil
}
return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24, [4:]
}
func ( []byte) (uint64, []byte) {
if len() < 4 {
return 0, nil
}
return uint64([3]) | uint64([2])<<8 | uint64([1])<<16 | uint64([0])<<24, [4:]
}
func ( []byte) (uint64, []byte) {
if len() < 8 {
return 0, nil
}
return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24 | uint64([4])<<32 | uint64([5])<<40 | uint64([6])<<48 | uint64([7])<<56, [8:]
}
func ( []byte) (uint64, []byte) {
if len() < 8 {
return 0, nil
}
return uint64([7]) | uint64([6])<<8 | uint64([5])<<16 | uint64([4])<<24 | uint64([3])<<32 | uint64([2])<<40 | uint64([1])<<48 | uint64([0])<<56, [8:]
}
func ( []byte) (*Profile, error) {
var func([]byte) (uint64, []byte)
var , , , , uint64
for _, = range cpuInts {
var []byte
, = ()
, = ()
, = ()
, = ()
, = ()
if != nil && == 0 && == 3 && == 0 && > 0 && == 0 {
=
return cpuProfile(, int64(), )
}
if != nil && == 0 && == 3 && == 1 && > 0 && == 0 {
=
return javaCPUProfile(, int64(), )
}
}
return nil, errUnrecognized
}
func ( []byte, int64, func( []byte) (uint64, []byte)) (*Profile, error) {
:= &Profile{
Period: * 1000,
PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
SampleType: []*ValueType{
{Type: "samples", Unit: "count"},
{Type: "cpu", Unit: "nanoseconds"},
},
}
var error
if , _, = parseCPUSamples(, , true, ); != nil {
return nil,
}
func ( []byte, func( []byte) (uint64, []byte), bool, *Profile) ([]byte, map[uint64]*Location, error) {
:= make(map[uint64]*Location)
for len() > 0 {
var , uint64
, = ()
, = ()
if == nil || > uint64(len()/4) {
return nil, nil, errUnrecognized
}
var []*Location
:= make([]uint64, )
for := 0; < int(); ++ {
[], = ()
}
return , , nil
}
func ( []byte) ( *Profile, error) {
:= bufio.NewScanner(bytes.NewBuffer())
if !.Scan() {
if := .Err(); != nil {
return nil,
}
return nil, errUnrecognized
}
= &Profile{}
:= ""
:= false
:= .Text()
.PeriodType = &ValueType{Type: "space", Unit: "bytes"}
if := heapHeaderRE.FindStringSubmatch(); != nil {
, .Period, , = parseHeapHeader()
if != nil {
return nil,
}
} else if = growthHeaderRE.FindStringSubmatch(); != nil {
.Period = 1
} else if = fragmentationHeaderRE.FindStringSubmatch(); != nil {
.Period = 1
} else {
return nil, errUnrecognized
}
.SampleType = []*ValueType{
{Type: "alloc_objects", Unit: "count"},
{Type: "alloc_space", Unit: "bytes"},
{Type: "inuse_objects", Unit: "count"},
{Type: "inuse_space", Unit: "bytes"},
}
} else {
.SampleType = []*ValueType{
{Type: "objects", Unit: "count"},
{Type: "space", Unit: "bytes"},
}
}
:= make(map[uint64]*Location)
for .Scan() {
:= strings.TrimSpace(.Text())
if isSpaceOrComment() {
continue
}
if isMemoryMapSentinel() {
break
}
, , , := parseHeapSample(, .Period, , )
if != nil {
return nil,
}
var []*Location
--
:= []
if [] == nil {
= &Location{
Address: ,
}
.Location = append(.Location, )
[] =
}
= append(, )
}
.Sample = append(.Sample, &Sample{
Value: ,
Location: ,
NumLabel: map[string][]int64{"bytes": {}},
})
}
if := .Err(); != nil {
return nil,
}
if := parseAdditionalSections(, ); != nil {
return nil,
}
return , nil
}
func ( string) ( string, int64, bool, error) {
:= heapHeaderRE.FindStringSubmatch()
if == nil {
return "", 0, false, errUnrecognized
}
if len([6]) > 0 {
if , = strconv.ParseInt([6], 10, 64); != nil {
return "", 0, false, errUnrecognized
}
}
if ([3] != [1] && [3] != "0") || ([4] != [2] && [4] != "0") {
= true
}
switch [5] {
case "heapz_v2", "heap_v2":
return "v2", , , nil
case "heapprofile":
return "", 1, , nil
case "heap":
return "v2", / 2, , nil
default:
return "", 0, false, errUnrecognized
}
}
:= func(, string, string) error {
, := strconv.ParseInt(, 10, 64)
if != nil {
return fmt.Errorf("malformed sample: %s: %v", , )
}
, := strconv.ParseInt(, 10, 64)
if != nil {
return fmt.Errorf("malformed sample: %s: %v", , )
}
if == 0 && != 0 {
return fmt.Errorf("%s count was 0 but %s bytes was %d", , , )
}
if != 0 {
= /
if == "v2" {
, = scaleHeapSample(, , )
}
}
= append(, , )
return nil
}
if {
if := ([3], [4], "allocation"); != nil {
return nil, 0, nil,
}
}
if := ([1], [2], "inuse"); != nil {
return nil, 0, nil,
}
, = parseHexAddresses([5])
if != nil {
return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", , )
}
return , , , nil
}
func ( []byte) (*Profile, error) {
:= bufio.NewScanner(bytes.NewBuffer())
if !.Scan() {
if := .Err(); != nil {
return nil,
}
return nil, errUnrecognized
}
switch := .Text(); {
case strings.HasPrefix(, "--- contentionz "):
case strings.HasPrefix(, "--- mutex:"):
case strings.HasPrefix(, "--- contention:"):
default:
return nil, errUnrecognized
}
:= &Profile{
PeriodType: &ValueType{Type: "contentions", Unit: "count"},
Period: 1,
SampleType: []*ValueType{
{Type: "contentions", Unit: "count"},
{Type: "delay", Unit: "nanoseconds"},
},
}
const = "="
for .Scan() {
:= .Text()
if = strings.TrimSpace(); isSpaceOrComment() {
continue
}
if strings.HasPrefix(, "---") {
break
}
:= strings.SplitN(, , 2)
if len() != 2 {
break
}
, := strings.TrimSpace([0]), strings.TrimSpace([1])
var error
switch {
case "cycles/second":
if , = strconv.ParseInt(, 0, 64); != nil {
return nil, errUnrecognized
}
case "sampling period":
if .Period, = strconv.ParseInt(, 0, 64); != nil {
return nil, errUnrecognized
}
case "ms since reset":
, := strconv.ParseInt(, 0, 64)
if != nil {
return nil, errUnrecognized
}
.DurationNanos = * 1000 * 1000
return nil, errUnrecognized
return nil, errUnrecognized
case "discarded samples":
default:
return nil, errUnrecognized
}
}
if := .Err(); != nil {
return nil,
}
:= make(map[uint64]*Location)
for {
:= strings.TrimSpace(.Text())
if strings.HasPrefix(, "---") {
break
}
if !isSpaceOrComment() {
, , := parseContentionSample(, .Period, )
if != nil {
return nil,
}
var []*Location
func ( string, , int64) ( []int64, []uint64, error) {
:= contentionSampleRE.FindStringSubmatch()
if == nil {
return nil, nil, errUnrecognized
}
, := strconv.ParseInt([1], 10, 64)
if != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", , )
}
, := strconv.ParseInt([2], 10, 64)
if != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", , )
}
for .Scan() && isSpaceOrComment(.Text()) {
}
:= .Text()
for .Scan() {
if = .Text(); isMemoryMapSentinel() || strings.HasPrefix(, "-") {
break
}
}
} else if := threadStartRE.FindStringSubmatch(); len() != 4 {
return nil, errUnrecognized
}
:= &Profile{
SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
PeriodType: &ValueType{Type: "thread", Unit: "count"},
Period: 1,
}
for !isMemoryMapSentinel() {
if strings.HasPrefix(, "---- no stack trace for") {
= ""
break
}
if := threadStartRE.FindStringSubmatch(); len() != 4 {
return nil, errUnrecognized
}
var []uint64
var error
, , = parseThreadSample()
if != nil {
return nil,
}
func ( *bufio.Scanner) ( string, []uint64, error) {
var string
:= false
for .Scan() {
= strings.TrimSpace(.Text())
if == "" {
continue
}
if strings.HasPrefix(, "---") {
break
}
if strings.Contains(, "same as previous thread") {
= true
continue
}
, := parseHexAddresses()
if != nil {
return "", nil, fmt.Errorf("malformed sample: %s: %v", , )
}
= append(, ...)
}
if := .Err(); != nil {
return "", nil,
}
if {
return , nil, nil
}
return , , nil
}
func ( *bufio.Scanner, *Profile) error {
for !isMemoryMapSentinel(.Text()) && .Scan() {
}
if := .Err(); != nil {
return
}
return .ParseMemoryMapFromScanner()
}
func ( io.Reader) ([]*Mapping, error) {
:= bufio.NewScanner()
return parseProcMapsFromScanner()
}
func ( *bufio.Scanner) ([]*Mapping, error) {
var []*Mapping
var []string
const = "="
:= strings.NewReplacer()
for .Scan() {
:= .Replace(removeLoggingInfo(.Text()))
, := parseMappingEntry()
if != nil {
func ( string) string {
if := logInfoRE.FindStringIndex(); != nil {
return [[1]:]
}
return
}
func ( *Profile) ( io.Reader) error {
return .ParseMemoryMapFromScanner(bufio.NewScanner())
}
func ( *Profile) ( *bufio.Scanner) error {
, := parseProcMapsFromScanner()
if != nil {
return
}
.Mapping = append(.Mapping, ...)
.massageMappings()
.remapLocationIDs()
.remapFunctionIDs()
.remapMappingIDs()
return nil
}
func ( string) (*Mapping, error) {
var , , , , , string
if := procMapsRE.FindStringSubmatch(); len() == 6 {
, , , , = [1], [2], [3], [4], [5]
} else if := briefMapsRE.FindStringSubmatch(); len() == 7 {
, , , , , = [1], [2], [3], [4], [5], [6]
} else {
return nil, errUnrecognized
}
var error
:= &Mapping{
File: ,
BuildID: ,
}
return nil, nil
}
if .Start, = strconv.ParseUint(, 16, 64); != nil {
return nil, errUnrecognized
}
if .Limit, = strconv.ParseUint(, 16, 64); != nil {
return nil, errUnrecognized
}
if != "" {
if .Offset, = strconv.ParseUint(, 16, 64); != nil {
return nil, errUnrecognized
}
}
return , nil
}
var memoryMapSentinels = []string{
"--- Memory map: ---",
"MAPPED_LIBRARIES:",
}
func ( string) bool {
for , := range memoryMapSentinels {
if strings.Contains(, ) {
return true
}
}
return false
}
func ( *Profile) () {
switch {
case isProfileType(, heapzSampleTypes):
.DropFrames, .KeepFrames = allocRxStr, allocSkipRxStr
case isProfileType(, contentionzSampleTypes):
.DropFrames, .KeepFrames = lockRxStr, ""
default:
.DropFrames, .KeepFrames = cpuProfilerRxStr, ""
}
}
var heapzSampleTypes = [][]string{
{"allocations", "size"}, // early Go pprof profiles
{"objects", "space"},
{"inuse_objects", "inuse_space"},
{"alloc_objects", "alloc_space"},
{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles
}
var contentionzSampleTypes = [][]string{
{"contentions", "delay"},
}
func ( *Profile, [][]string) bool {
:= .SampleType
:
for , := range {
if len() != len() {
continue
}
for := range {
if [].Type != [] {
continue
}
}
return true
}
return false
}
`calloc`,
`cfree`,
`malloc`,
`free`,
`memalign`,
`do_memalign`,
`(__)?posix_memalign`,
`pvalloc`,
`valloc`,
`realloc`,
`tcmalloc::.*`,
`tc_calloc`,
`tc_cfree`,
`tc_malloc`,
`tc_free`,
`tc_memalign`,
`tc_posix_memalign`,
`tc_pvalloc`,
`tc_valloc`,
`tc_realloc`,
`tc_new`,
`tc_delete`,
`tc_newarray`,
`tc_deletearray`,
`tc_new_nothrow`,
`tc_newarray_nothrow`,
`malloc_zone_malloc`,
`malloc_zone_calloc`,
`malloc_zone_valloc`,
`malloc_zone_realloc`,
`malloc_zone_memalign`,
`malloc_zone_free`,
`runtime\..*`,
`BaseArena::.*`,
`(::)?do_malloc_no_errno`,
`(::)?do_malloc_pages`,
`(::)?do_malloc`,
`DoSampledAllocation`,
`MallocedMemBlock::MallocedMemBlock`,
`_M_allocate`,
`__builtin_(vec_)?delete`,
`__builtin_(vec_)?new`,
`__gnu_cxx::new_allocator::allocate`,
`__libc_malloc`,
`__malloc_alloc_template::allocate`,
`allocate`,
`cpp_alloc`,
`operator new(\[\])?`,
`simple_alloc::allocate`,
}, `|`)
`runtime\.panic`,
`runtime\.reflectcall`,
`runtime\.call[0-9]*`,
}, `|`)
var cpuProfilerRxStr = strings.Join([]string{
`ProfileData::Add`,
`ProfileData::prof_handler`,
`CpuProfiler::prof_handler`,
`__pthread_sighandler`,
`__restore`,
}, `|`)
var lockRxStr = strings.Join([]string{
`RecordLockProfileData`,
`(base::)?RecordLockProfileData.*`,
`(base::)?SubmitMutexProfileData.*`,
`(base::)?SubmitSpinLockProfileData.*`,
`(base::Mutex::)?AwaitCommon.*`,
`(base::Mutex::)?Unlock.*`,
`(base::Mutex::)?UnlockSlow.*`,
`(base::Mutex::)?ReaderUnlock.*`,
`(base::MutexLock::)?~MutexLock.*`,
`(Mutex::)?AwaitCommon.*`,
`(Mutex::)?Unlock.*`,
`(Mutex::)?UnlockSlow.*`,
`(Mutex::)?ReaderUnlock.*`,
`(MutexLock::)?~MutexLock.*`,
`(SpinLock::)?Unlock.*`,
`(SpinLock::)?SlowUnlock.*`,
`(SpinLockHolder::)?~SpinLockHolder.*`,
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |