memclr optimization and structs

201 views
Skip to first unread message

sam....@pinterest.com

unread,
Apr 14, 2017, 7:02:24 PM4/14/17
to golang-nuts
Hi, 

I've been looking into why some of our code wasn't resulting in the memclr optimization originally introduced in response to https://github.com/golang/go/issues/5373. I'm still a bit unclear on why this happens. Here is the code that triggers the issue for me:


package foo


import (

  "testing"

)


type Foo struct {

   H string

   A int64

   B int64

   C int64

}



func BenchmarkClear4(b *testing.B) {


  b.RunParallel(func(pb *testing.PB) {

    testFoo := make([]Foo, 100)

    for pb.Next() {

          for i := range testFoo {

              testFoo[i] = Foo{}

          }

    }

  })

}

For me (go 1.8) the above snippet results in asm that doesn't make use of memclr. On the other hand, when I comment out field C in the struct above then the code does make use of the optimization. Similarly, when I change the first field from string to int64, it also works. Is this expected? If so, is there some documentation for the criteria for the optimization?

/Sam

Keith Randall

unread,
Apr 15, 2017, 4:31:28 AM4/15/17
to golang-nuts
The value being zeroed must not have any pointers.  This is a change from 1.7 and is part of the requirement for the hybrid write barrier (part of making garbage collection pauses smaller).

Konstantin Khomoutov

unread,
Apr 15, 2017, 7:18:51 AM4/15/17
to golan...@googlegroups.com, sam....@pinterest.com, Keith Randall
On Sat, 15 Apr 2017 01:31:27 -0700 (PDT)
"'Keith Randall' via golang-nuts" <golan...@googlegroups.com> wrote:

> > I've been looking into why some of our code wasn't resulting in the
> > memclr optimization originally introduced in response to
> > https://github.com/golang/go/issues/5373.
[...]
> > type Foo struct {
> > H string
> > A int64
> > B int64
> > C int64
> > }
[...]
> > For me (go 1.8) the above snippet results in asm that doesn't make
> > use of memclr. On the other hand, when I comment out field C in the
> > struct above then the code does make use of the optimization.
> > Similarly, when I change the first field from string to int64, it
> > also works.
[...]
> The value being zeroed must not have any pointers. This is a change
> from 1.7 and is part of the requirement for the hybrid write barrier
> <https://gist.github.com/aclements/4b5e2758310032dbdb030d7648b5ab32>
> (part of making garbage collection pauses smaller).

Sorry, I might be missing the point completely but while this perfectly
explains using of the memclr optimization after removal of H but how
can it explain also enabling of memclr after removal of C which is not
a pointer?

T L

unread,
Apr 16, 2017, 7:13:23 AM4/16/17
to golang-nuts, sam....@pinterest.com, k...@google.com

Looks if H is present, it will optimized as memclrHasPointers, otherwise, it will optimized as memclrNoHeapPointers.
But it is really weird that not optimization made if C is present.

 

Keith Randall

unread,
Apr 17, 2017, 5:33:49 PM4/17/17
to golang-nuts, sam....@pinterest.com, k...@google.com
Sorry, my first look at this was incorrect.  Changing the pointer to a scalar does re-enable the optimization.  But so does making it less than 4 words in size.

The optimization fails because the loop body gets translated to { tmp := Foo{}; testFoo[i] = tmp } by the order pass (cmd/compile/internal/gc/order.go:417-423), and that confuses the later optimization.  It only does this transformation for large (>4 word) and write-barrier-requiring types.

In any case, this is fixed at tip.  It was fixed as part of redoing the write barrier logic.
Reply all
Reply to author
Forward
0 new messages