// printCountProfile prints a countProfile at the specified debug level. func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { prof := &profile.Profile{ PeriodType: &profile.ValueType{Type: name, Unit: "count"}, Period: 1, SampleType: []*profile.ValueType{{Type: name, Unit: "count"}}, } locations := make(map[uint64]*profile.Location) count := map[string]int{} index := map[string]int{} var keys []string n := p.Len() for i := 0; i < n; i++ { k := makeKey(p.Stack(i)) if count[k] == 0 { index[k] = i keys = append(keys, k) } count[k]++ } sort.Sort(&keysByCount{keys, count}) // Print stacks, listing count on first occurrence of a unique stack. for _, k := range keys { stk := p.Stack(index[k]) if c := count[k]; c != 0 { locs := make([]*profile.Location, 0, len(stk)) for _, addr := range stk { addr := uint64(addr) // Adjust all frames by -1 to land on the call instruction. addr-- loc := locations[addr] if loc == nil { loc = &profile.Location{ Address: addr, } locations[addr] = loc prof.Location = append(prof.Location, loc) } locs = append(locs, loc) } prof.Sample = append(prof.Sample, &profile.Sample{ Location: locs, Value: []int64{int64(c)}, }) delete(count, k) } } prof.RemapAll() protopprof.Symbolize(prof) return prof.Write(w) }
func profileWriter(w io.Writer) { var buf bytes.Buffer for { data := runtime.CPUProfile() buf.Write(data) if data == nil { break } } p, err := protopprof.TranslateCPUProfile(buf.Bytes(), cpu.startTime) if err != nil { panic(err) } p.RemapAll() protopprof.CleanupDuplicateLocations(p) protopprof.Symbolize(p) p.Write(w) cpu.done <- true }
// writeBlock writes the current blocking profile to w. func writeBlock(w io.Writer, debug int) error { var p []runtime.BlockProfileRecord n, ok := runtime.BlockProfile(nil) for { // Code by analogy with writeBlock func p = make([]runtime.BlockProfileRecord, n+50) n, ok = runtime.BlockProfile(p) if ok { p = p[:n] break } } sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) prof := &profile.Profile{ PeriodType: &profile.ValueType{Type: "contentions", Unit: "count"}, Period: 1, SampleType: []*profile.ValueType{ {Type: "contentions", Unit: "count"}, {Type: "delay", Unit: "nanoseconds"}, }, } cpuHz := runtime_cyclesPerSecond() locs := make(map[uint64]*profile.Location) for i := range p { r := &p[i] var v1, v2 int64 v1 = r.Cycles v2 = r.Count if prof.Period > 0 { if cpuHz > 0 { cpuGHz := float64(cpuHz) / 1e9 v1 = int64(float64(v1) * float64(prof.Period) / cpuGHz) } v2 = v2 * prof.Period } value := []int64{v2, v1} var sloc []*profile.Location for _, pc := range r.Stack() { addr := uint64(pc) addr-- loc := locs[addr] if locs[addr] == nil { loc = &profile.Location{ Address: addr, } prof.Location = append(prof.Location, loc) locs[addr] = loc } sloc = append(sloc, loc) } prof.Sample = append(prof.Sample, &profile.Sample{ Value: value, Location: sloc, }) } prof.RemapAll() protopprof.Symbolize(prof) return prof.Write(w) }
// writeHeap writes the current runtime heap profile to w. func writeHeap(w io.Writer, debug int) error { // Find out how many records there are (MemProfile(nil, true)), // allocate that many records, and get the data. // There's a race—more records might be added between // the two calls—so allocate a few extra records for safety // and also try again if we're very unlucky. // The loop should only execute one iteration in the common case. var p []runtime.MemProfileRecord n, ok := runtime.MemProfile(nil, true) for { p = make([]runtime.MemProfileRecord, n+50) n, ok = runtime.MemProfile(p, true) if ok { p = p[0:n] break } } sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() }) var total runtime.MemProfileRecord for i := range p { r := &p[i] total.AllocBytes += r.AllocBytes total.AllocObjects += r.AllocObjects total.FreeBytes += r.FreeBytes total.FreeObjects += r.FreeObjects } prof := &profile.Profile{ PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"}, SampleType: []*profile.ValueType{ {Type: "alloc_objects", Unit: "count"}, {Type: "alloc_space", Unit: "bytes"}, {Type: "inuse_objects", Unit: "count"}, {Type: "inuse_space", Unit: "bytes"}, }, Period: int64(runtime.MemProfileRate), } locs := make(map[uint64]*(profile.Location)) for i := range p { var v1, v2, v3, v4, blocksize int64 r := &p[i] v1, v2 = int64(r.InUseObjects()), int64(r.InUseBytes()) v3, v4 = int64(r.AllocObjects), int64(r.AllocBytes) if (v1 == 0 && v2 != 0) || (v3 == 0 && v4 != 0) { return fmt.Errorf("error writing memory profile: inuse object count was 0 but inuse bytes was %d", v2) } else { if v1 != 0 { blocksize = v2 / v1 v1, v2 = scaleHeapSample(v1, v2, prof.Period) } if v3 != 0 { v3, v4 = scaleHeapSample(v3, v4, prof.Period) } } value := []int64{v1, v2, v3, v4} var sloc []*profile.Location for _, pc := range r.Stack() { addr := uint64(pc) addr-- loc := locs[addr] if locs[addr] == nil { loc = &(profile.Location{ Address: addr, }) prof.Location = append(prof.Location, loc) locs[addr] = loc } sloc = append(sloc, loc) } prof.Sample = append(prof.Sample, &profile.Sample{ Value: value, Location: sloc, NumLabel: map[string][]int64{"bytes": {blocksize}}, }) } prof.RemapAll() protopprof.Symbolize(prof) return prof.Write(w) }