github.com/fjl/memsize@v0.0.2/memsize_test.go (about)

     1  package memsize
     2  
     3  import (
     4  	"testing"
     5  	"unsafe"
     6  )
     7  
     8  const (
     9  	sizeofSlice     = unsafe.Sizeof([]byte{})
    10  	sizeofMap       = unsafe.Sizeof(map[string]string{})
    11  	sizeofInterface = unsafe.Sizeof((interface{})(nil))
    12  	sizeofString    = unsafe.Sizeof("")
    13  	sizeofWord      = unsafe.Sizeof(uintptr(0))
    14  	sizeofChan      = unsafe.Sizeof(make(chan struct{}))
    15  )
    16  
    17  type (
    18  	struct16 struct {
    19  		x, y uint64
    20  	}
    21  	structptr struct {
    22  		x   uint32
    23  		cld *structptr
    24  	}
    25  	structuint32ptr struct {
    26  		x *uint32
    27  	}
    28  	structmultiptr struct {
    29  		s1 *structptr
    30  		u1 *structuint32ptr
    31  		s2 *structptr
    32  		u2 *structuint32ptr
    33  		s3 *structptr
    34  		u3 *structuint32ptr
    35  	}
    36  	structarrayptr struct {
    37  		x *uint64
    38  		a [10]uint64
    39  	}
    40  	structiface struct {
    41  		s *struct16
    42  		x interface{}
    43  	}
    44  	struct64array  struct{ array64 }
    45  	structslice    struct{ s []uint32 }
    46  	structstring   struct{ s string }
    47  	structloop     struct{ s *structloop }
    48  	structptrslice struct{ s *structslice }
    49  	array64        [64]byte
    50  )
    51  
    52  func TestTotal(t *testing.T) {
    53  	tests := []struct {
    54  		name string
    55  		v    interface{}
    56  		want uintptr
    57  	}{
    58  		{
    59  			name: "struct16",
    60  			v:    &struct16{},
    61  			want: 16,
    62  		},
    63  		{
    64  			name: "structptr_nil",
    65  			v:    &structptr{},
    66  			want: 2 * sizeofWord,
    67  		},
    68  		{
    69  			name: "structptr",
    70  			v:    &structptr{cld: &structptr{}},
    71  			want: 2 * 2 * sizeofWord,
    72  		},
    73  		{
    74  			name: "structptr_loop",
    75  			v: func() *structptr {
    76  				v := &structptr{}
    77  				v.cld = v
    78  				return v
    79  			}(),
    80  			want: 2 * sizeofWord,
    81  		},
    82  		{
    83  			name: "structmultiptr_loop",
    84  			v: func() *structmultiptr {
    85  				v1 := &structptr{x: 1}
    86  				v2 := &structptr{x: 2, cld: v1}
    87  				return &structmultiptr{s1: v1, s2: v1, s3: v2}
    88  			}(),
    89  			want: 6*sizeofWord /* structmultiptr */ + 2*2*sizeofWord, /* structptr */
    90  		},
    91  		{
    92  			name: "structmultiptr_interior",
    93  			v: func() *structmultiptr {
    94  				v1 := &structptr{x: 1}
    95  				v2 := &structptr{x: 2}
    96  				return &structmultiptr{
    97  					// s1 is scanned before u1, which has a reference to a field of s1.
    98  					s1: v1,
    99  					u1: &structuint32ptr{x: &v1.x},
   100  					// This one goes the other way around: u2, which has a reference to a
   101  					// field of s3 is scanned before s3.
   102  					u2: &structuint32ptr{x: &v2.x},
   103  					s3: v2,
   104  				}
   105  			}(),
   106  			want: 6*sizeofWord /* structmultiptr */ + 2*2*sizeofWord /* structptr */ + 2*sizeofWord, /* structuint32ptr */
   107  		},
   108  		{
   109  			name: "struct64array",
   110  			v:    &struct64array{},
   111  			want: 64,
   112  		},
   113  		{
   114  			name: "structptrslice",
   115  			v:    &structptrslice{&structslice{s: []uint32{1, 2, 3}}},
   116  			want: sizeofWord + sizeofSlice + 3*4,
   117  		},
   118  		{
   119  			name: "array_unadressable",
   120  			v: func() *map[[3]uint64]struct{} {
   121  				v := map[[3]uint64]struct{}{
   122  					{1, 2, 3}: struct{}{},
   123  				}
   124  				return &v
   125  			}(),
   126  			want: sizeofMap + 3*8,
   127  		},
   128  		{
   129  			name: "structslice",
   130  			v:    &structslice{s: []uint32{1, 2, 3}},
   131  			want: sizeofSlice + 3*4,
   132  		},
   133  		{
   134  			name: "structloop",
   135  			v: func() *structloop {
   136  				v := new(structloop)
   137  				v.s = v
   138  				return v
   139  			}(),
   140  			want: sizeofWord,
   141  		},
   142  		{
   143  			name: "array64",
   144  			v:    &array64{},
   145  			want: 64,
   146  		},
   147  		{
   148  			name: "byteslice",
   149  			v:    &[]byte{1, 2, 3},
   150  			want: sizeofSlice + 3,
   151  		},
   152  		{
   153  			name: "slice3_ptrval",
   154  			v:    &[]*struct16{{}, {}, {}},
   155  			want: sizeofSlice + 3*sizeofWord + 3*16,
   156  		},
   157  		{
   158  			name: "map0",
   159  			v:    &map[uint64]uint64{},
   160  			want: sizeofMap,
   161  		},
   162  		{
   163  			name: "map3",
   164  			v:    &map[uint64]uint64{1: 1, 2: 2, 3: 3},
   165  			want: sizeofMap + 3*8 /* keys */ + 3*8, /* values */
   166  		},
   167  		{
   168  			name: "map3_ptrval",
   169  			v:    &map[uint64]*struct16{1: {}, 2: {}, 3: {}},
   170  			want: sizeofMap + 3*8 /* keys */ + 3*sizeofWord /* value pointers */ + 3*16, /* values */
   171  		},
   172  		{
   173  			name: "map3_ptrkey",
   174  			v:    &map[*struct16]uint64{{x: 1}: 1, {x: 2}: 2, {x: 3}: 3},
   175  			want: sizeofMap + 3*sizeofWord /* key pointers */ + 3*16 /* keys */ + 3*8, /* values */
   176  		},
   177  		{
   178  			name: "map_interface",
   179  			v:    &map[interface{}]interface{}{"aa": uint64(1)},
   180  			want: sizeofMap + sizeofInterface + sizeofString + 2 /* key */ + sizeofInterface + 8, /* value */
   181  		},
   182  		{
   183  			name: "pointerpointer",
   184  			v: func() **uint64 {
   185  				i := uint64(0)
   186  				p := &i
   187  				return &p
   188  			}(),
   189  			want: sizeofWord + 8,
   190  		},
   191  		{
   192  			name: "structstring",
   193  			v:    &structstring{"123"},
   194  			want: sizeofString + 3,
   195  		},
   196  		{
   197  			name: "slices_samearray",
   198  			v: func() *[3][]byte {
   199  				backarray := [64]byte{}
   200  				return &[3][]byte{
   201  					backarray[16:],
   202  					backarray[4:16],
   203  					backarray[0:4],
   204  				}
   205  			}(),
   206  			want: 3*sizeofSlice + 64,
   207  		},
   208  		{
   209  			name: "slices_nil",
   210  			v: func() *[2][]byte {
   211  				return &[2][]byte{nil, nil}
   212  			}(),
   213  			want: 2 * sizeofSlice,
   214  		},
   215  		{
   216  			name: "slices_overlap_total",
   217  			v: func() *[2][]byte {
   218  				backarray := [32]byte{}
   219  				return &[2][]byte{backarray[:], backarray[:]}
   220  			}(),
   221  			want: 2*sizeofSlice + 32,
   222  		},
   223  		{
   224  			name: "slices_overlap",
   225  			v: func() *[4][]uint16 {
   226  				backarray := [32]uint16{}
   227  				return &[4][]uint16{
   228  					backarray[2:4],
   229  					backarray[10:12],
   230  					backarray[20:25],
   231  					backarray[:],
   232  				}
   233  			}(),
   234  			want: 4*sizeofSlice + 32*2,
   235  		},
   236  		{
   237  			name: "slices_overlap_array",
   238  			v: func() *struct {
   239  				a [32]byte
   240  				s [2][]byte
   241  			} {
   242  				v := struct {
   243  					a [32]byte
   244  					s [2][]byte
   245  				}{}
   246  				v.s[0] = v.a[2:4]
   247  				v.s[1] = v.a[5:8]
   248  				return &v
   249  			}(),
   250  			want: 32 + 2*sizeofSlice,
   251  		},
   252  		{
   253  			name: "interface",
   254  			v:    &[2]interface{}{uint64(0), &struct16{}},
   255  			want: 2*sizeofInterface + 8 + 16,
   256  		},
   257  		{
   258  			name: "interface_nil",
   259  			v:    &[2]interface{}{nil, nil},
   260  			want: 2 * sizeofInterface,
   261  		},
   262  		{
   263  			name: "structiface_slice",
   264  			v:    &structiface{x: make([]byte, 10)},
   265  			want: sizeofWord + sizeofInterface + sizeofSlice + 10,
   266  		},
   267  		{
   268  			name: "structiface_pointer",
   269  			v: func() *structiface {
   270  				s := &struct16{1, 2}
   271  				return &structiface{s: s, x: &s.x}
   272  			}(),
   273  			want: sizeofWord + 16 + sizeofInterface,
   274  		},
   275  		{
   276  			name: "empty_chan",
   277  			v: func() *chan uint64 {
   278  				c := make(chan uint64)
   279  				return &c
   280  			}(),
   281  			want: sizeofChan,
   282  		},
   283  		{
   284  			name: "empty_closed_chan",
   285  			v: func() *chan uint64 {
   286  				c := make(chan uint64)
   287  				close(c)
   288  				return &c
   289  			}(),
   290  			want: sizeofChan,
   291  		},
   292  		{
   293  			name: "empty_chan_buffer",
   294  			v: func() *chan uint64 {
   295  				c := make(chan uint64, 10)
   296  				return &c
   297  			}(),
   298  			want: sizeofChan + 10*8,
   299  		},
   300  		{
   301  			name: "chan_buffer",
   302  			v: func() *chan uint64 {
   303  				c := make(chan uint64, 10)
   304  				for i := 0; i < 8; i++ {
   305  					c <- 0
   306  				}
   307  				return &c
   308  			}(),
   309  			want: sizeofChan + 10*8,
   310  		},
   311  		{
   312  			name: "closed_chan_buffer",
   313  			v: func() *chan uint64 {
   314  				c := make(chan uint64, 10)
   315  				for i := 0; i < 8; i++ {
   316  					c <- 0
   317  				}
   318  				close(c)
   319  				return &c
   320  			}(),
   321  			want: sizeofChan + 10*8,
   322  		},
   323  		{
   324  			name: "chan_buffer_escan",
   325  			v: func() *chan *struct16 {
   326  				c := make(chan *struct16, 10)
   327  				for i := 0; i < 8; i++ {
   328  					c <- &struct16{x: uint64(i)}
   329  				}
   330  				return &c
   331  			}(),
   332  			want: sizeofChan + 10*sizeofWord + 8*16,
   333  		},
   334  		{
   335  			name: "closed_chan_buffer_escan",
   336  			v: func() *chan *struct16 {
   337  				c := make(chan *struct16, 10)
   338  				for i := 0; i < 8; i++ {
   339  					c <- &struct16{x: uint64(i)}
   340  				}
   341  				close(c)
   342  				return &c
   343  			}(),
   344  			want: sizeofChan + 10*sizeofWord + 8*16,
   345  		},
   346  		{
   347  			name: "nil_chan",
   348  			v: func() *chan *struct16 {
   349  				var c chan *struct16
   350  				return &c
   351  			}(),
   352  			want: sizeofChan,
   353  		},
   354  	}
   355  	for _, test := range tests {
   356  		t.Run(test.name, func(t *testing.T) {
   357  			size := Scan(test.v)
   358  			if size.Total != test.want {
   359  				t.Errorf("total=%d, want %d", size.Total, test.want)
   360  				t.Logf("\n%s", size.Report())
   361  			}
   362  		})
   363  	}
   364  }