Repository: go
Issue: runtime: memory and performance degradation
Labels: compiler/runtime

Below is the program, I am running it with 1.4 and current tip. There are significant regressions with binary size, execution time and memory consumption.
Binary size on 1.4 3581368, binary size on tip is 4096280.
Below are results of running it with `TIME="%e %M" time`:

```
1.4
4.04 3035492
4.38 3035496
4.66 3035500
4.51 3035500
4.42 3035504
4.34 3035500
4.20 3035496
3.87 3035496
4.07 3035496
4.15 3035504
4.28 3035492

tip
4.93 3009044
5.30 4910668
5.49 2978652
5.05 3929244
5.86 2980032
5.91 3929368
5.24 2980052
5.26 3929196
5.64 2980976
5.60 2979944
5.15 3929228
5.36 3929224
4.97 2980096
6.36 3929472
4.77 3929172
```

1.4 reliably consumes 3GB, while 1.5 can consume 3GB or 4GB or 5GB.
There also seems to be a performance regression of about 30%.

Memory consumption instability and variance seems to be the most troublesome.
tip should not consume significantly more than 1.4.

``` go
package gob

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "io"
    "reflect"
    "testing"

    "github.com/dvyukov/go-fuzz/examples/fuzz"
)

type X struct {
    A int
    B string
    C float64
    D []byte
    E interface{}
    F complex128
    G []interface{}
    H *int
    I **int
    J *X
    K map[string]int
}

func init() {
    gob.Register(X{})
}

func TestT(t *testing.T) {
    data :=     "#\xff\x99\x03\x01\x01\x03RT\x19\x01\xff\x9a\x00\x01\xfb\x00\aA\x01" +
    "\x04\x00\x01\x01B\x01\f\x00\x01\x01C\x01\b\x00\x00\x00\x16\xff\x9a\x01" +
    "\"\x01\x05hello\x01\u007f\xff\xff\xff\xf0\xf9!\t@\x00"

    Fuzz([]byte(data))
}

func Fuzz(data []byte) int {
    score := 0
    for _, ctor := range []func() interface{}{
        func() interface{} { return nil },
        func() interface{} { return new(int) },
        func() interface{} { return new(string) },
        func() interface{} { return new(float64) },
        func() interface{} { return new([]byte) },
        func() interface{} { return new(interface{}) },
        func() interface{} { return new(complex128) },
        func() interface{} { m := make(map[int]int); return &m },
        func() interface{} { m := make(map[string]interface{}); return &m },
        func() interface{} { return new(X) },
    } {
        v := ctor()
        dec := gob.NewDecoder(bytes.NewReader(data))
        if dec.Decode(v) != nil {
            continue
        }
        dec.Decode(ctor())
        score = 1
        if ctor() == nil {
            continue
        }
        b1 := new(bytes.Buffer)
        if err := gob.NewEncoder(b1).Encode(v); err != nil {
            panic(err)
        }
        v1 := reflect.ValueOf(ctor())
        err := gob.NewDecoder(bytes.NewReader(data)).DecodeValue(v1)
        if err != nil {
            panic(err)
        }
        if !fuzz.DeepEqual(v, v1.Interface()) {
            fmt.Printf("v0: %#v\n", reflect.ValueOf(v).Elem().Interface())
            fmt.Printf("v1: %#v\n", v1.Elem().Interface())
            panic(fmt.Sprintf("values not equal %T", v))
        }
        b2 := new(bytes.Buffer)
        err = gob.NewEncoder(b2).EncodeValue(v1)
        if err != nil {
            panic(err)
        }
        v2 := ctor()
        dec1 := gob.NewDecoder(b1)
        if err := dec1.Decode(v2); err != nil {
            panic(err)
        }
        if err := dec1.Decode(ctor()); err != io.EOF {
            panic(err)
        }
        if vv, ok := v.(*X); ok {
            fix(vv)
        }
        if !fuzz.DeepEqual(v, v2) {
            fmt.Printf("v0: %#v\n", reflect.ValueOf(v).Elem().Interface())
            fmt.Printf("v2: %#v\n", reflect.ValueOf(v2).Elem().Interface())
            panic(fmt.Sprintf("values not equal 2 %T", v))
        }
    }
    return score
}

func fix(vv *X) {
    // See https://github.com/golang/go/issues/11119
    if vv.I != nil && (*vv.I == nil || **vv.I == 0) {
        // If input contains "I:42 I:null", then I will be in this weird state.
        // It is effectively nil, but DeepEqual does not handle such case.
        vv.I = nil
    }
    if vv.H != nil && *vv.H == 0 {
        vv.H = nil
    }
    if vv.J != nil {
        fix(vv.J)
    }
}
```

go version devel +a1aafdb Tue Sep 15 16:12:59 2015 +0000 linux/amd64