Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

看内容 #19979

Closed
niubaoshu opened this issue Apr 14, 2017 · 9 comments
Closed

看内容 #19979

niubaoshu opened this issue Apr 14, 2017 · 9 comments

Comments

@niubaoshu
Copy link

niubaoshu commented Apr 14, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.8 darwin/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN="/Users/niubaoshu/work/go/bin"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/niubaoshu/work/go"
GORACE=""
GOROOT="/Users/niubaoshu/repos/go"
GOTOOLDIR="/Users/niubaoshu/repos/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/jz/fj17bn1j3tg7s0g2yv_4wsyh0000gn/T/go-build530042778=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.

https://play.golang.org/p/2XtE2FVceD

What did you expect to see?

go test -bench="." -benchmem inter_test.go
BenchmarkT-8 2000000000 0.34 ns/op 0 B/op 0 allocs/op
BenchmarkT2-8 50000000 27.0 ns/op 8 B/op 1 allocs/op

What did you see instead?

为什么BenchmarkT2-8 需要分配一次内存?
猜测是正常的函数调用做了优化,所以不需要分配内存。
但是为什么var fff = ccc 就想要分配内存了

Why does BenchmarkT2-8 need to allocate memory once?
Guess that the normal function call is optimized so there is no need to allocate memory.
But why is var fff = ccc want to allocate memory

@ALTree
Copy link
Member

ALTree commented Apr 14, 2017

If the problem is the allocation, it looks like it's fixed on tip.

go1.8:

BenchmarkT-4    	2000000000	         0.39 ns/op	       0 B/op	       0 allocs/op
BenchmarkT2-4   	50000000	        27.5 ns/op	       8 B/op	       1 allocs/op

tip:

BenchmarkT-4    	2000000000	         0.33 ns/op	       0 B/op	       0 allocs/op
BenchmarkT2-4   	1000000000	         2.63 ns/op	       0 B/op	       0 allocs/op

@bradfitz
Copy link
Contributor

Yes, the translation looks like it's about the allocation.

@niubaoshu
Copy link
Author

niubaoshu commented May 21, 2017

@ALTree the issues still exist on go1.8.1 and master .what is tip version?

@bradfitz
Copy link
Contributor

@niubaoshu "tip" means "master". Same thing but different word.

@ALTree
Copy link
Member

ALTree commented May 21, 2017

I ran the benchmark in your post on master (both on 14 April when we closed this and again, now) and the allocation is gone. Are you seeing something different?

@niubaoshu
Copy link
Author

niubaoshu commented May 22, 2017

package main

import "testing"

func BenchmarkF1(b *testing.B) {
for i := 0; i < b.N; i++ {
f1(i)
}
}

func BenchmarkC1(b *testing.B) {
for i := 0; i < b.N; i++ {
c1(i)
}
}

func BenchmarkF2(b *testing.B) {
for i := 0; i < b.N; i++ {
f2(i)
}
}

func BenchmarkC2(b *testing.B) {
for i := 0; i < b.N; i++ {
c2(i)
}
}
func BenchmarkF3(b *testing.B) {
for i := 0; i < b.N; i++ {
f3(i)
}
}

func BenchmarkC3(b *testing.B) {
for i := 0; i < b.N; i++ {
c3(i)
}
}
func BenchmarkF4(b *testing.B) {
for i := 0; i < b.N; i++ {
f4(i)
}
}

func BenchmarkC4(b *testing.B) {
for i := 0; i < b.N; i++ {
c4(i)
}
}

var c1 = f1
var c2 = f2
var c3 = f3
var c4 = f4

func f1(a ...interface{}) {}
func f2(a interface{}) {}
func f3(a ...int) {}
func f4(a int) {}

go test -bench=.* -benchmem malloc_test.go

on go1.8.1 version
output:
BenchmarkF1-4 500000000 3.16 ns/op 0 B/op 0 allocs/op
BenchmarkC1-4 20000000 64.0 ns/op 24 B/op 2 allocs/op
BenchmarkF2-4 2000000000 0.35 ns/op 0 B/op 0 allocs/op
BenchmarkC2-4 50000000 29.8 ns/op 8 B/op 1 allocs/op
BenchmarkF3-4 1000000000 2.84 ns/op 0 B/op 0 allocs/op
BenchmarkC3-4 100000000 22.3 ns/op 8 B/op 1 allocs/op
BenchmarkF4-4 2000000000 0.32 ns/op 0 B/op 0 allocs/op
BenchmarkC4-4 1000000000 2.52 ns/op 0 B/op 0 allocs/op
PASS
ok command-line-arguments 14.383s

@ALTree
Copy link
Member

ALTree commented May 22, 2017

Looks like it may be an escape analysis limitation? Take the first two:

func BenchmarkF1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		f1(i)
	}
}

func BenchmarkC1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		c1(i)
	}
}

var c1 = f1
func f1(a ...interface{}) {}

-m -m says that i in the f1(i) does not escape:

BenchmarkF1 i does not escape

but in c1(i) it does:

i escapes to heap
	from c1(i) (parameter to indirect call) at ./prova_test.go:13:5

same for f2(i) and c2(i). This is where it happens:

// We know nothing!

Not sure this is expected or not, or if we want to open an issue about a possible optimization. Maybe cc @dr2chase knows.

@niubaoshu
Copy link
Author

@ALTree OK, thank you!

@randall77
Copy link
Contributor

The global variable causes the pessimism here. We don't analyze the whole program to find all assignments to global variables, so although f1 is the current value of c1, maybe another function will be assigned to c1 somewhere else. So we must assume the interface{} and [1]interface{} escape.
Because c1 isn't exported, we could actually do better here. This is another example of devirtualizing calls, similar to #19361.

@golang golang locked and limited conversation to collaborators May 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants