Description
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version
)?
go version devel +212c9479e3 Tue May 15 16:29:04 2018 +0000 linux/amd64
Does this issue reproduce with the latest release?
n/a: this relies on changes in tip
.
What operating system and processor architecture are you using (go env
)?
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/myitcv/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/myitcv/gostuff"
GORACE=""
GOROOT="/home/myitcv/gos"
GOTMPDIR=""
GOTOOLDIR="/home/myitcv/gos/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build404056765=/tmp/go-build -gno-record-gcc-switches"
What did you do?
cd `mktemp -d`
export GOPATH=$PWD
mkdir -p src/example.com
cat <<EOD > src/example.com/main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world!")
}
EOD
cat <<EOD > src/example.com/main_test.go
package main_test
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
"testing"
)
const (
testPkg = "example.com"
)
func BenchmarkGoRun(b *testing.B) {
for n := 0; n < b.N; n++ {
cmd := exec.Command("go", "run", testPkg)
out, err := cmd.CombinedOutput()
if err != nil {
panic(fmt.Errorf("failed to %v: %v\n%s", strings.Join(cmd.Args, " "), err, out))
}
}
}
func BenchmarkGoBuild(b *testing.B) {
tf, err := ioutil.TempFile("", "")
if err != nil {
b.Fatalf("failed to create temp file: %v", err)
}
defer os.Remove(tf.Name())
{
cmd := exec.Command("go", "build", "-o", tf.Name(), testPkg)
out, err := cmd.CombinedOutput()
if err != nil {
b.Fatalf("%v failed: %v\n%s", strings.Join(cmd.Args, " "), err, out)
}
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
cmd := exec.Command(tf.Name())
out, err := cmd.CombinedOutput()
if err != nil {
b.Fatalf("%v failed: %v\n%s", strings.Join(cmd.Args, " "), err, out)
}
}
}
EOD
go test -test.bench . example.com
What did you expect to see?
The benchmark with go run example.com
to be more comparable with the benchmark that runs a binary directly.
What did you see instead?
The go run example.com
benchmark is ~180 times slower.
goos: linux
goarch: amd64
pkg: example.com
BenchmarkGoRun-8 10 163497281 ns/op
BenchmarkGoBuild-8 2000 893443 ns/op
PASS
ok example.com 4.260s
I recall @rsc mentioning somewhere (can't recall where) that the result of go run pkg
is not cached, which I think accounts for the difference above.
One of the major benefits of the go run pkg
form is that it is possible to unambiguously identify the program in question. My particular use case is //go:generate
directives, where it then becomes possible to calculate the go generate
dependency graph.
Ideally I would like to replace all of my //go:generate abc
directives with //go:generate example.com/p/abc
, but the difference in speeds observed above makes this infeasible.
So I'm raising this as an issue to discuss whether it would be worth caching the output of go run pkg
. I can't claim to understand any of the pros/cons here so would appreciate thoughts.