diff --git a/structslop.go b/structslop.go index 7a2d762..276265d 100644 --- a/structslop.go +++ b/structslop.go @@ -125,11 +125,12 @@ func run(pass *analysis.Pass) (interface{}, error) { ) if r.sloppy() { msg = fmt.Sprintf( - "struct has size %d (size class %d), could be %d (size class %d), you'll save %.2f%% if you rearrange it to:\n%s\n", + "struct has size %d (size class %d), could be %d (size class %d), you'll save %.2f%% (%d bytes) if you rearrange it to:\n%s\n", r.oldGcSize, r.oldRuntimeSize, r.newGcSize, r.newRuntimeSize, + r.savingsPercent(), r.savings(), buf.String(), ) @@ -207,8 +208,12 @@ func (r result) sloppy() bool { return r.oldRuntimeSize > r.newRuntimeSize } -func (r result) savings() float64 { - return float64(r.oldRuntimeSize-r.newRuntimeSize) / float64(r.oldRuntimeSize) * 100 +func (r result) savingsPercent() float64 { + return float64(r.savings()) / float64(r.oldRuntimeSize) * 100 +} + +func (r result) savings() int64 { + return r.oldRuntimeSize - r.newRuntimeSize } func mapFieldIdx(s *types.Struct) map[*types.Var]int { diff --git a/testdata/src/include-test-files/p.go b/testdata/src/include-test-files/p.go index 4253f2b..59a4f6a 100644 --- a/testdata/src/include-test-files/p.go +++ b/testdata/src/include-test-files/p.go @@ -14,7 +14,7 @@ package p -type s struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` +type s struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` x uint32 y uint64 z uint32 diff --git a/testdata/src/struct/p.go b/testdata/src/struct/p.go index b33d660..1792d1c 100644 --- a/testdata/src/struct/p.go +++ b/testdata/src/struct/p.go @@ -27,13 +27,13 @@ type s2 struct { j int } -type s3 struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` +type s3 struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` x uint32 y uint64 z uint32 } -type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` b bool i1 int i2 int @@ -41,9 +41,9 @@ type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(si _ [0]func() } -// should be good, the struct has size 32, can be rearrange to have size 24, but runtime allocator +// should be good, the struct has size 32, can be rearranged to have size 24, but runtime allocator // allocate the same size class 32. -type s5 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` +type s5 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` x uint32 y uint64 z *s @@ -56,7 +56,7 @@ type s6 struct { // should be good, see #16 index uintptr } -type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*httptest.Server\n\tw uint64\n\tx uint32\n\tz uint32\n}` +type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% \(16 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*httptest.Server\n\tw uint64\n\tx uint32\n\tz uint32\n}` x uint32 y uint64 t *httptest.Server @@ -64,7 +64,7 @@ type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(si w uint64 } -type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*s\n\tw uint64\n\tx uint32\n\tz uint32\n}` +type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% \(16 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*s\n\tw uint64\n\tx uint32\n\tz uint32\n}` x uint32 y uint64 t *s @@ -73,7 +73,7 @@ type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(si } // Struct which combines multiple fields of the same type, see issue #41. -type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` b bool i1, i2 int a3 [3]bool @@ -81,7 +81,7 @@ type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(si } // Preserve comments. -type s10 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s10 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` b bool // b is bool i1, i2 int // i1, i2 are int a3 [3]bool // a3 is array of bool diff --git a/testdata/src/struct/p.go.golden b/testdata/src/struct/p.go.golden index 137238d..5585b10 100644 --- a/testdata/src/struct/p.go.golden +++ b/testdata/src/struct/p.go.golden @@ -27,13 +27,13 @@ type s2 struct { j int } -type s3 struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` +type s3 struct { // want `struct has size 24 \(size class 24\), could be 16 \(size class 16\), you'll save 33.33% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tx uint32\n\tz uint32\n}` y uint64 x uint32 z uint32 } -type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` _ [0]func() i1 int i2 int @@ -41,9 +41,9 @@ type s4 struct { // want `struct has size 40 \(size class 48\), could be 24 \(si b bool } -// should be good, the struct has size 32, can be rearrange to have size 24, but runtime allocator +// should be good, the struct has size 32, can be rearranged to have size 24, but runtime allocator // allocate the same size class 32. -type s5 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` +type s5 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` y uint64 z *s x uint32 @@ -56,7 +56,7 @@ type s6 struct { // should be good, see #16 index uintptr } -type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*httptest.Server\n\tw uint64\n\tx uint32\n\tz uint32\n}` +type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% \(16 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*httptest.Server\n\tw uint64\n\tx uint32\n\tz uint32\n}` y uint64 t *httptest.Server w uint64 @@ -64,7 +64,7 @@ type s7 struct { // want `struct has size 40 \(size class 48\), could be 32 \(si z uint32 } -type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*s\n\tw uint64\n\tx uint32\n\tz uint32\n}` +type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(size class 32\), you'll save 33.33% \(16 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tt \*s\n\tw uint64\n\tx uint32\n\tz uint32\n}` y uint64 t *s w uint64 @@ -73,7 +73,7 @@ type s8 struct { // want `struct has size 40 \(size class 48\), could be 32 \(si } // Struct which combines multiple fields of the same type, see issue #41. -type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` _ [0]func() i1, i2 int a3 [3]bool @@ -81,7 +81,7 @@ type s9 struct { // want `struct has size 40 \(size class 48\), could be 24 \(si } // Preserve comments. -type s10 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` +type s10 struct { // want `struct has size 40 \(size class 48\), could be 24 \(size class 24\), you'll save 50.00% \(24 bytes\) if you rearrange it to:\nstruct {\n\t_ \[0\]func\(\)\n\ti1 int\n\ti2 int\n\ta3 \[3\]bool\n\tb bool\n}` _ [0]func() i1, i2 int // i1, i2 are int a3 [3]bool // a3 is array of bool diff --git a/testdata/src/verbose/p.go b/testdata/src/verbose/p.go index 47bddc8..9eba43e 100644 --- a/testdata/src/verbose/p.go +++ b/testdata/src/verbose/p.go @@ -20,7 +20,7 @@ type s1 struct { // want `struct has size 1 \(size class 8\)` b bool } -type s3 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` +type s3 struct { // want `struct has size 32 \(size class 32\), could be 24 \(size class 24\), you'll save 25.00% \(8 bytes\) if you rearrange it to:\nstruct {\n\ty uint64\n\tz \*s\n\tx uint32\n\tt uint32\n}` x uint32 y uint64 z *s