xref: /aosp_15_r20/external/starlark-go/starlark/profile_test.go (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
1// Copyright 2019 The Bazel 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
5package starlark_test
6
7import (
8	"bytes"
9	"fmt"
10	"io/ioutil"
11	"os"
12	"os/exec"
13	"strings"
14	"testing"
15
16	"go.starlark.net/starlark"
17)
18
19// TestProfile is a simple integration test that the profiler
20// emits minimally plausible pprof-compatible output.
21func TestProfile(t *testing.T) {
22	prof, err := ioutil.TempFile("", "profile_test")
23	if err != nil {
24		t.Fatal(err)
25	}
26	defer prof.Close()
27	defer os.Remove(prof.Name())
28	if err := starlark.StartProfile(prof); err != nil {
29		t.Fatal(err)
30	}
31
32	const src = `
33def fibonacci(n):
34	res = list(range(n))
35	for i in res[2:]:
36		res[i] = res[i-2] + res[i-1]
37	return res
38
39fibonacci(100000)
40`
41
42	thread := new(starlark.Thread)
43	if _, err := starlark.ExecFile(thread, "foo.star", src, nil); err != nil {
44		_ = starlark.StopProfile()
45		t.Fatal(err)
46	}
47	if err := starlark.StopProfile(); err != nil {
48		t.Fatal(err)
49	}
50	prof.Sync()
51	cmd := exec.Command("go", "tool", "pprof", "-top", prof.Name())
52	cmd.Stderr = new(bytes.Buffer)
53	cmd.Stdout = new(bytes.Buffer)
54	if err := cmd.Run(); err != nil {
55		t.Fatalf("pprof failed: %v; output=<<%s>>", err, cmd.Stderr)
56	}
57
58	// Typical output (may vary by go release):
59	//
60	// Type: wall
61	// Time: Apr 4, 2019 at 11:10am (EDT)
62	// Duration: 251.62ms, Total samples = 250ms (99.36%)
63	// Showing nodes accounting for 250ms, 100% of 250ms total
64	//  flat  flat%   sum%        cum   cum%
65	// 320ms   100%   100%      320ms   100%  fibonacci
66	//     0     0%   100%      320ms   100%  foo.star
67	//
68	// We'll assert a few key substrings are present.
69	got := fmt.Sprint(cmd.Stdout)
70	for _, want := range []string{
71		"flat%",
72		"fibonacci",
73		"foo.star",
74	} {
75		if !strings.Contains(got, want) {
76			t.Errorf("output did not contain %q", want)
77		}
78	}
79	if t.Failed() {
80		t.Logf("stderr=%v", cmd.Stderr)
81		t.Logf("stdout=%v", cmd.Stdout)
82	}
83}
84