Skip to content

Commit 0d8a3b2

Browse files
committed
cmd/compile: add TestIntendedInlining from runtime
Move it from the runtime package, as we will soon add more packages and functions for it to check. The test used the testEnv func, which cleaned certain environment variables from a command, so it was moved to internal/testenv under a more descriptive (and less ambiguous) name. Add a simple godoc to it too. For #21851. Change-Id: I6f39c1f23b45377718355fafe66ffd87047d8ab6 Reviewed-on: https://go-review.googlesource.com/63550 Run-TryBot: Daniel Martí <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ilya Tocar <[email protected]>
1 parent d02477e commit 0d8a3b2

File tree

7 files changed

+96
-84
lines changed

7 files changed

+96
-84
lines changed
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2017 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 gc
6+
7+
import (
8+
"bytes"
9+
"internal/testenv"
10+
"os/exec"
11+
"testing"
12+
)
13+
14+
// TestIntendedInlining tests that specific runtime functions are inlined.
15+
// This allows refactoring for code clarity and re-use without fear that
16+
// changes to the compiler will cause silent performance regressions.
17+
func TestIntendedInlining(t *testing.T) {
18+
if testing.Short() && testenv.Builder() == "" {
19+
t.Skip("skipping in short mode")
20+
}
21+
testenv.MustHaveGoRun(t)
22+
t.Parallel()
23+
24+
// want is the list of function names that should be inlined.
25+
want := []string{"tophash", "add", "(*bmap).keys", "bucketShift", "bucketMask"}
26+
27+
m := make(map[string]bool, len(want))
28+
for _, s := range want {
29+
m[s] = true
30+
}
31+
32+
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "build", "-a", "-gcflags=-m", "runtime"))
33+
out, err := cmd.CombinedOutput()
34+
if err != nil {
35+
t.Logf("%s", out)
36+
t.Fatal(err)
37+
}
38+
lines := bytes.Split(out, []byte{'\n'})
39+
for _, x := range lines {
40+
f := bytes.Split(x, []byte(": can inline "))
41+
if len(f) < 2 {
42+
continue
43+
}
44+
fn := bytes.TrimSpace(f[1])
45+
delete(m, string(fn))
46+
}
47+
48+
for s := range m {
49+
t.Errorf("function %s not inlined", s)
50+
}
51+
}

src/internal/testenv/testenv.go

+22
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,25 @@ func SkipFlakyNet(t *testing.T) {
209209
t.Skip("skipping test on builder known to have frequent network failures")
210210
}
211211
}
212+
213+
// CleanCmdEnv will fill cmd.Env with the environment, excluding certain
214+
// variables that could modify the behavior of the Go tools such as
215+
// GODEBUG and GOTRACEBACK.
216+
func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd {
217+
if cmd.Env != nil {
218+
panic("environment already set")
219+
}
220+
for _, env := range os.Environ() {
221+
// Exclude GODEBUG from the environment to prevent its output
222+
// from breaking tests that are trying to parse other command output.
223+
if strings.HasPrefix(env, "GODEBUG=") {
224+
continue
225+
}
226+
// Exclude GOTRACEBACK for the same reason.
227+
if strings.HasPrefix(env, "GOTRACEBACK=") {
228+
continue
229+
}
230+
cmd.Env = append(cmd.Env, env)
231+
}
232+
return cmd
233+
}

src/runtime/crash_cgo_test.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
113113
t.Fatal(err)
114114
}
115115

116-
got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
116+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
117117
if err != nil {
118118
t.Fatalf("exit status: %v\n%s", err, got)
119119
}
@@ -136,7 +136,7 @@ func TestCgoExternalThreadSignal(t *testing.T) {
136136
t.Fatal(err)
137137
}
138138

139-
got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
139+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
140140
if err != nil {
141141
t.Fatalf("exit status: %v\n%s", err, got)
142142
}
@@ -203,14 +203,14 @@ func TestCgoCheckBytes(t *testing.T) {
203203
const tries = 10
204204
var tot1, tot2 time.Duration
205205
for i := 0; i < tries; i++ {
206-
cmd := testEnv(exec.Command(exe, "CgoCheckBytes"))
206+
cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
207207
cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
208208

209209
start := time.Now()
210210
cmd.Run()
211211
d1 := time.Since(start)
212212

213-
cmd = testEnv(exec.Command(exe, "CgoCheckBytes"))
213+
cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
214214
cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
215215

216216
start = time.Now()
@@ -283,7 +283,7 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) {
283283
t.Fatal(err)
284284
}
285285

286-
got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput()
286+
got, err := testenv.CleanCmdEnv(exec.Command(exe, runArg)).CombinedOutput()
287287
if err != nil {
288288
if testenv.Builder() == "linux-amd64-alpine" {
289289
// See Issue 18243 and Issue 19938.
@@ -295,7 +295,7 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) {
295295
defer os.Remove(fn)
296296

297297
for try := 0; try < 2; try++ {
298-
cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1"))
298+
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1"))
299299
// Check that pprof works both with and without explicit executable on command line.
300300
if try == 0 {
301301
cmd.Args = append(cmd.Args, exe, fn)
@@ -359,7 +359,7 @@ func TestRaceProf(t *testing.T) {
359359
t.Fatal(err)
360360
}
361361

362-
got, err := testEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
362+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
363363
if err != nil {
364364
t.Fatal(err)
365365
}
@@ -388,7 +388,7 @@ func TestRaceSignal(t *testing.T) {
388388
t.Fatal(err)
389389
}
390390

391-
got, err := testEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
391+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
392392
if err != nil {
393393
t.Logf("%s\n", got)
394394
t.Fatal(err)
@@ -431,7 +431,7 @@ func TestCatchPanic(t *testing.T) {
431431
}
432432

433433
for _, early := range []bool{true, false} {
434-
cmd := testEnv(exec.Command(exe, "CgoCatchPanic"))
434+
cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
435435
// Make sure a panic results in a crash.
436436
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
437437
if early {

src/runtime/crash_test.go

+7-26
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,6 @@ func TestMain(m *testing.M) {
3232
os.Exit(status)
3333
}
3434

35-
func testEnv(cmd *exec.Cmd) *exec.Cmd {
36-
if cmd.Env != nil {
37-
panic("environment already set")
38-
}
39-
for _, env := range os.Environ() {
40-
// Exclude GODEBUG from the environment to prevent its output
41-
// from breaking tests that are trying to parse other command output.
42-
if strings.HasPrefix(env, "GODEBUG=") {
43-
continue
44-
}
45-
// Exclude GOTRACEBACK for the same reason.
46-
if strings.HasPrefix(env, "GOTRACEBACK=") {
47-
continue
48-
}
49-
cmd.Env = append(cmd.Env, env)
50-
}
51-
return cmd
52-
}
53-
5435
var testprog struct {
5536
sync.Mutex
5637
dir string
@@ -70,7 +51,7 @@ func runTestProg(t *testing.T, binary, name string) string {
7051
t.Fatal(err)
7152
}
7253

73-
cmd := testEnv(exec.Command(exe, name))
54+
cmd := testenv.CleanCmdEnv(exec.Command(exe, name))
7455
var b bytes.Buffer
7556
cmd.Stdout = &b
7657
cmd.Stderr = &b
@@ -139,7 +120,7 @@ func buildTestProg(t *testing.T, binary string, flags ...string) (string, error)
139120
exe := filepath.Join(testprog.dir, name+".exe")
140121
cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...)
141122
cmd.Dir = "testdata/" + binary
142-
out, err := testEnv(cmd).CombinedOutput()
123+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
143124
if err != nil {
144125
target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
145126
testprog.target[name] = target
@@ -158,14 +139,14 @@ var (
158139
func checkStaleRuntime(t *testing.T) {
159140
staleRuntimeOnce.Do(func() {
160141
// 'go run' uses the installed copy of runtime.a, which may be out of date.
161-
out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
142+
out, err := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
162143
if err != nil {
163144
staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
164145
return
165146
}
166147
if string(out) != "false\n" {
167148
t.Logf("go list -f {{.Stale}} runtime:\n%s", out)
168-
out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.StaleReason}}", "runtime")).CombinedOutput()
149+
out, err := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.StaleReason}}", "runtime")).CombinedOutput()
169150
if err != nil {
170151
t.Logf("go list -f {{.StaleReason}} failed: %v", err)
171152
}
@@ -468,15 +449,15 @@ func TestMemPprof(t *testing.T) {
468449
t.Fatal(err)
469450
}
470451

471-
got, err := testEnv(exec.Command(exe, "MemProf")).CombinedOutput()
452+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput()
472453
if err != nil {
473454
t.Fatal(err)
474455
}
475456
fn := strings.TrimSpace(string(got))
476457
defer os.Remove(fn)
477458

478459
for try := 0; try < 2; try++ {
479-
cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top"))
460+
cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top"))
480461
// Check that pprof works both with and without explicit executable on command line.
481462
if try == 0 {
482463
cmd.Args = append(cmd.Args, exe, fn)
@@ -586,7 +567,7 @@ func TestPanicRace(t *testing.T) {
586567
const tries = 10
587568
retry:
588569
for i := 0; i < tries; i++ {
589-
got, err := testEnv(exec.Command(exe, "PanicRace")).CombinedOutput()
570+
got, err := testenv.CleanCmdEnv(exec.Command(exe, "PanicRace")).CombinedOutput()
590571
if err == nil {
591572
t.Logf("try %d: program exited successfully, should have failed", i+1)
592573
continue

src/runtime/crash_unix_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ func TestCrashDumpsAllThreads(t *testing.T) {
6565

6666
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
6767
cmd.Dir = dir
68-
out, err := testEnv(cmd).CombinedOutput()
68+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
6969
if err != nil {
7070
t.Fatalf("building source: %v\n%s", err, out)
7171
}
7272

7373
cmd = exec.Command(filepath.Join(dir, "a.exe"))
74-
cmd = testEnv(cmd)
74+
cmd = testenv.CleanCmdEnv(cmd)
7575
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
7676

7777
// Set GOGC=off. Because of golang.org/issue/10958, the tight
@@ -184,7 +184,7 @@ func TestPanicSystemstack(t *testing.T) {
184184

185185
t.Parallel()
186186
cmd := exec.Command(os.Args[0], "testPanicSystemstackInternal")
187-
cmd = testEnv(cmd)
187+
cmd = testenv.CleanCmdEnv(cmd)
188188
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
189189
pr, pw, err := os.Pipe()
190190
if err != nil {
@@ -249,7 +249,7 @@ func TestSignalExitStatus(t *testing.T) {
249249
if err != nil {
250250
t.Fatal(err)
251251
}
252-
err = testEnv(exec.Command(exe, "SignalExitStatus")).Run()
252+
err = testenv.CleanCmdEnv(exec.Command(exe, "SignalExitStatus")).Run()
253253
if err == nil {
254254
t.Error("test program succeeded unexpectedly")
255255
} else if ee, ok := err.(*exec.ExitError); !ok {

src/runtime/runtime-gdb_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func testGdbPython(t *testing.T, cgo bool) {
132132

133133
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
134134
cmd.Dir = dir
135-
out, err := testEnv(cmd).CombinedOutput()
135+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
136136
if err != nil {
137137
t.Fatalf("building source %v\n%s", err, out)
138138
}
@@ -278,7 +278,7 @@ func TestGdbBacktrace(t *testing.T) {
278278
}
279279
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
280280
cmd.Dir = dir
281-
out, err := testEnv(cmd).CombinedOutput()
281+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
282282
if err != nil {
283283
t.Fatalf("building source %v\n%s", err, out)
284284
}
@@ -348,7 +348,7 @@ func TestGdbAutotmpTypes(t *testing.T) {
348348
}
349349
cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", "a.exe")
350350
cmd.Dir = dir
351-
out, err := testEnv(cmd).CombinedOutput()
351+
out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
352352
if err != nil {
353353
t.Fatalf("building source %v\n%s", err, out)
354354
}

src/runtime/runtime_test.go

-42
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
package runtime_test
66

77
import (
8-
"bytes"
9-
"internal/testenv"
108
"io"
11-
"os/exec"
129
. "runtime"
1310
"runtime/debug"
1411
"strings"
@@ -357,42 +354,3 @@ func TestVersion(t *testing.T) {
357354
t.Fatalf("cr/nl in version: %q", vers)
358355
}
359356
}
360-
361-
// TestIntendedInlining tests that specific runtime functions are inlined.
362-
// This allows refactoring for code clarity and re-use without fear that
363-
// changes to the compiler will cause silent performance regressions.
364-
func TestIntendedInlining(t *testing.T) {
365-
if testing.Short() && testenv.Builder() == "" {
366-
t.Skip("skipping in short mode")
367-
}
368-
testenv.MustHaveGoRun(t)
369-
t.Parallel()
370-
371-
// want is the list of function names that should be inlined.
372-
want := []string{"tophash", "add", "(*bmap).keys", "bucketShift", "bucketMask"}
373-
374-
m := make(map[string]bool, len(want))
375-
for _, s := range want {
376-
m[s] = true
377-
}
378-
379-
cmd := testEnv(exec.Command(testenv.GoToolPath(t), "build", "-a", "-gcflags=-m", "runtime"))
380-
out, err := cmd.CombinedOutput()
381-
if err != nil {
382-
t.Logf("%s", out)
383-
t.Fatal(err)
384-
}
385-
lines := bytes.Split(out, []byte{'\n'})
386-
for _, x := range lines {
387-
f := bytes.Split(x, []byte(": can inline "))
388-
if len(f) < 2 {
389-
continue
390-
}
391-
fn := bytes.TrimSpace(f[1])
392-
delete(m, string(fn))
393-
}
394-
395-
for s := range m {
396-
t.Errorf("function %s not inlined", s)
397-
}
398-
}

0 commit comments

Comments
 (0)