// Tests TranslateCPUProfile parses correct sampling period in an otherwise empty cpu profile. func TestTranlateCPUProfileSamplingPeriod(t *testing.T) { // A test server with mock cpu profile data. var buf bytes.Buffer startTime := time.Now() b := createEmptyProfileWithPeriod(t, 2000) p, err := TranslateCPUProfile(b.Bytes(), startTime) if err != nil { t.Fatalf("translate failed: %v", err) } if err := p.Write(&buf); err != nil { t.Fatalf("write failed: %v", err) } p, err = profile.Parse(&buf) if err != nil { t.Fatalf("Could not parse Profile profile: %v", err) } // Expected PeriodType and SampleType. expectedPeriodType := &profile.ValueType{Type: "cpu", Unit: "nanoseconds"} expectedSampleType := []*profile.ValueType{ {Type: "samples", Unit: "count"}, {Type: "cpu", Unit: "nanoseconds"}, } if p.Period != 2000*1000 || !reflect.DeepEqual(p.PeriodType, expectedPeriodType) || !reflect.DeepEqual(p.SampleType, expectedSampleType) || p.Sample != nil { t.Fatalf("Unexpected Profile fields") } }
func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) { p, err := profile.Parse(bytes.NewReader(valBytes)) if err != nil { t.Fatal(err) } for _, sample := range p.Sample { count := uintptr(sample.Value[0]) stk := make([]uintptr, len(sample.Location)) for i := range sample.Location { stk[i] = uintptr(sample.Location[i].Address) } f(count, stk) } }
func TestGoroutineCounts(t *testing.T) { if runtime.GOOS == "openbsd" { testenv.SkipFlaky(t, 15156) } c := make(chan int) for i := 0; i < 100; i++ { if i%10 == 0 { go func1(c) continue } if i%2 == 0 { go func2(c) continue } go func3(c) } time.Sleep(10 * time.Millisecond) // let goroutines block on channel var w bytes.Buffer goroutineProf := Lookup("goroutine") // Check debug profile goroutineProf.WriteTo(&w, 1) prof := w.String() if !containsInOrder(prof, "\n50 @ ", "\n40 @", "\n10 @", "\n1 @") { t.Errorf("expected sorted goroutine counts:\n%s", prof) } // Check proto profile w.Reset() goroutineProf.WriteTo(&w, 0) p, err := profile.Parse(&w) if err != nil { t.Errorf("error parsing protobuf profile: %v", err) } if err := p.CheckValid(); err != nil { t.Errorf("protobuf profile is invalid: %v", err) } if !containsCounts(p, []int64{50, 40, 10, 1}) { t.Errorf("expected count profile to contain goroutines with counts %v, got %v", []int64{50, 40, 10, 1}, p) } close(c) time.Sleep(10 * time.Millisecond) // let goroutines exit }
// Fetcher is the plugin.Fetcher version of FetchProfile. func Fetcher(source string, timeout time.Duration, ui plugin.UI) (*profile.Profile, error) { var f io.ReadCloser var err error url, err := url.Parse(source) if err == nil && url.Host != "" { f, err = FetchURL(source, timeout) } else { f, err = os.Open(source) } if err != nil { return nil, err } defer f.Close() return profile.Parse(f) }
// TestSampledHeapAllocProfile tests encoding of a memory profile from // runtime.MemProfileRecord data. func TestSampledHeapAllocProfile(t *testing.T) { if runtime.GOOS != "linux" { t.Skip("Test requires a system with /proc/self/maps") } // Figure out two addresses from /proc/self/maps. mmap, err := ioutil.ReadFile("/proc/self/maps") if err != nil { t.Fatal("Cannot read /proc/self/maps") } rd := bytes.NewReader(mmap) mprof := &profile.Profile{} if err = mprof.ParseMemoryMap(rd); err != nil { t.Fatalf("Cannot parse /proc/self/maps") } if len(mprof.Mapping) < 2 { // It is possible for a binary to only have 1 executable // region of memory. t.Skipf("need 2 or more mappings, got %v", len(mprof.Mapping)) } address1 := mprof.Mapping[0].Start address2 := mprof.Mapping[1].Start var buf bytes.Buffer rec, rate := testMemRecords(address1, address2) p := EncodeMemProfile(rec, rate, time.Now()) if err := p.Write(&buf); err != nil { t.Fatalf("Failed to write profile: %v", err) } p, err = profile.Parse(&buf) if err != nil { t.Fatalf("Could not parse Profile profile: %v", err) } // Expected PeriodType, SampleType and Sample. expectedPeriodType := &profile.ValueType{Type: "space", Unit: "bytes"} expectedSampleType := []*profile.ValueType{ {Type: "alloc_objects", Unit: "count"}, {Type: "alloc_space", Unit: "bytes"}, {Type: "inuse_objects", Unit: "count"}, {Type: "inuse_space", Unit: "bytes"}, } // Expected samples, with values unsampled according to the profiling rate. expectedSample := []*profile.Sample{ {Value: []int64{2050, 2099200, 1537, 1574400}, Location: []*profile.Location{ {ID: 1, Mapping: mprof.Mapping[0], Address: address1}, {ID: 2, Mapping: mprof.Mapping[1], Address: address2}, }}, {Value: []int64{1, 829411, 1, 829411}, Location: []*profile.Location{ {ID: 3, Mapping: mprof.Mapping[1], Address: address2 + 1}, {ID: 4, Mapping: mprof.Mapping[1], Address: address2 + 2}, }}, {Value: []int64{1, 829411, 0, 0}, Location: []*profile.Location{ {ID: 5, Mapping: mprof.Mapping[0], Address: address1 + 1}, {ID: 6, Mapping: mprof.Mapping[0], Address: address1 + 2}, {ID: 7, Mapping: mprof.Mapping[1], Address: address2 + 3}, }}, } if p.Period != 512*1024 { t.Fatalf("Sampling periods do not match") } if !reflect.DeepEqual(p.PeriodType, expectedPeriodType) { t.Fatalf("Period types do not match") } if !reflect.DeepEqual(p.SampleType, expectedSampleType) { t.Fatalf("Sample types do not match") } if !reflect.DeepEqual(p.Sample, expectedSample) { t.Fatalf("Samples do not match: Expected: %v, Got:%v", getSampleAsString(expectedSample), getSampleAsString(p.Sample)) } }