Home | History | Annotate | Download | only in protopprof
      1 // Copyright 2016 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package protopprof
      6 
      7 import (
      8 	"internal/pprof/profile"
      9 	"math"
     10 	"runtime"
     11 	"time"
     12 )
     13 
     14 // EncodeMemProfile converts MemProfileRecords to a Profile.
     15 func EncodeMemProfile(mr []runtime.MemProfileRecord, rate int64, t time.Time) *profile.Profile {
     16 	p := &profile.Profile{
     17 		Period:     rate,
     18 		PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"},
     19 		SampleType: []*profile.ValueType{
     20 			{Type: "alloc_objects", Unit: "count"},
     21 			{Type: "alloc_space", Unit: "bytes"},
     22 			{Type: "inuse_objects", Unit: "count"},
     23 			{Type: "inuse_space", Unit: "bytes"},
     24 		},
     25 		TimeNanos: int64(t.UnixNano()),
     26 	}
     27 
     28 	locs := make(map[uintptr]*profile.Location)
     29 	for _, r := range mr {
     30 		stack := r.Stack()
     31 		sloc := make([]*profile.Location, len(stack))
     32 		for i, addr := range stack {
     33 			loc := locs[addr]
     34 			if loc == nil {
     35 				loc = &profile.Location{
     36 					ID:      uint64(len(p.Location) + 1),
     37 					Address: uint64(addr),
     38 				}
     39 				locs[addr] = loc
     40 				p.Location = append(p.Location, loc)
     41 			}
     42 			sloc[i] = loc
     43 		}
     44 
     45 		ao, ab := scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
     46 		uo, ub := scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
     47 
     48 		p.Sample = append(p.Sample, &profile.Sample{
     49 			Value:    []int64{ao, ab, uo, ub},
     50 			Location: sloc,
     51 		})
     52 	}
     53 	if runtime.GOOS == "linux" {
     54 		addMappings(p)
     55 	}
     56 	return p
     57 }
     58 
     59 // scaleHeapSample adjusts the data from a heap Sample to
     60 // account for its probability of appearing in the collected
     61 // data. heap profiles are a sampling of the memory allocations
     62 // requests in a program. We estimate the unsampled value by dividing
     63 // each collected sample by its probability of appearing in the
     64 // profile. heap profiles rely on a poisson process to determine
     65 // which samples to collect, based on the desired average collection
     66 // rate R. The probability of a sample of size S to appear in that
     67 // profile is 1-exp(-S/R).
     68 func scaleHeapSample(count, size, rate int64) (int64, int64) {
     69 	if count == 0 || size == 0 {
     70 		return 0, 0
     71 	}
     72 
     73 	if rate <= 1 {
     74 		// if rate==1 all samples were collected so no adjustment is needed.
     75 		// if rate<1 treat as unknown and skip scaling.
     76 		return count, size
     77 	}
     78 
     79 	avgSize := float64(size) / float64(count)
     80 	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
     81 
     82 	return int64(float64(count) * scale), int64(float64(size) * scale)
     83 }
     84