Skip to content

cmd/compile: go statement desugaring results in additional allocations #46349

@qmuntal

Description

@qmuntal

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

go version devel go1.17-cca23a7 Sat May 22 00:51:17 2021 +0000 windows/amd64

Does this issue reproduce with the latest release?

Yes

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

go env Output
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\***\AppData\Local\go-build
set GOENV=C:\Users\***\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\***\go\pkg\mod
set GONOPROXY=*.hp.com
set GONOSUMDB=*.hp.com
set GOOS=windows
set GOPATH=C:\Users\***\go
set GOPRIVATE=*.hp.com
set GOPROXY=direct
set GOROOT=C:\Users\***\sdk\gotip
set GOSUMDB=off
set GOTMPDIR=
set GOTOOLDIR=C:\Users\***\sdk\gotip\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=devel go1.17-cca23a7 Sat May 22 00:51:17 2021 +0000
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=C:\Users\***\Documents\code\go3mf-thumbnailer\go.mod
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\***\AppData\Local\Temp\go-build497339627=/tmp/go-build -gno-record-gcc-switches

What did you do?

package main

import (
  "sync"
  "testing"
)

func BenchmarkAlloc(b *testing.B) {
  count := 10
  for n := 0; n < b.N; n++ {
    var wg sync.WaitGroup
    wg.Add(count)
    for i := 0; i < count; i++ {
        go func() {
          wg.Done()
        }()
     }
     wg.Wait()
  }
}

gotip test -run AAAA -bench BenchmarkAlloc -benchmem

What did you expect to see?

Same result as with go1.16.3 and gotip+GOEXPERIMENT=noregabi:

goos: windows
goarch: amd64
pkg: main
cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
BenchmarkCreate-8         211135              6922 ns/op              16 B/op          1 allocs/op
PASS
ok      main      2.048s

What did you see instead?

Alloc count grow linearly with the size of the loop:

goos: windows
goarch: amd64
pkg: main      
cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
BenchmarkCreate-8         183998              7023 ns/op             176 B/op         11 allocs/op
PASS
ok      main            2.575s

Notice that the number of allocations is directly proportional to the number of iterations inside the loop.

Context

I've found this regression while trying gotip in a private codebase. The provided benchmark is just a synthetic and minimal example I've found that reproduces what I'm seeing in the real code.

This is a memory profile snap for this benchmark, generated using go tool pprof -alloc_objects mem.out:

         .          .      6:)
         .          .      7:
         .          .      8:func BenchmarkCreate(b *testing.B) {
         .          .      9:   count := 10
         .          .     10:   for n := 0; n < b.N; n++ {
    131074     131074     11:           var wg sync.WaitGroup
         .          .     12:           wg.Add(count)
         .          .     13:           for i := 0; i < count; i++ {
   1507351    1507351     14:                   go func() {
         .          .     15:                           wg.Done()
         .          .     16:                   }()
         .          .     17:           }
         .          .     18:           wg.Wait()

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions