Skip to content

testing: Problems with memory allocation calculation for "json.Marshal" in Benchmarkc tests #68381

@Fgaoxing

Description

@Fgaoxing

Go version

Windows10/x86_64 Go1.22.5

Output of go env in your module/workspace:

set GO111MODULE=on
set GOARCH=amd64
set GOBIN=C:\Users\User\go\bin
set GOCACHE=C:\Users\User\AppData\Local\go-build
set GOENV=C:\Users\User\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\User\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\User\go
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22.5
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\User\AppData\Local\Temp\go-build1301597658=/tmp/go-build -gno-record-gcc-switches

What did you do?

package main_test

import (
	"encoding/json"
	"fmt"
	"reflect"
	"testing"
)

func BenchmarkMain(b *testing.B) {
	for i := 0; i < b.N; i++ {
		jsonObj := struct {
			Test1 string `json:"test1"`
			Test2 string `json:"test2"`
			Test3 string `json:"test3"`
			Test4 string `json:"test4"`
		}{
			Test1: "test1",
			Test2: "test2",
			Test3: "test3",
			Test4: "test4",
		}
		Used(json.Marshal(&jsonObj))
	}
}

func Used(...any) {}

I also changed "encoding/json" to disable caching.

// Line:1269
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) structFields {
	/*if f, ok := fieldCache.Load(t); ok {
		return f.(structFields)
	}
	f, _ := fieldCache.LoadOrStore(t, typeFields(t))*/
	return typeFields(t) //f.(structFields)
}

Normally func typeFields(t reflect.Type) structFields has a loop that iterates over the Fields of the structure, but this requires memory allocation, and the structure I created has 4 Fields, but he only allocates memory 2 times for this operation, which is unrealistic!

What did you see happen?

D:\Desktop\OAC\jsontest>go test -benchmem -bench=^Benchmark -v -cpuprofile=cpu.pprof
goos: windows
goarch: amd64
pkg: jsontest
cpu: Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
BenchmarkMain
BenchmarkMain-4          1899802               577.3 ns/op           144 B/op          2 allocs/op
PASS
ok      jsontest        1.777s

What did you expect to see?

D:\Desktop\OAC\jsontest>go test -benchmem -bench=^Benchmark -v -cpuprofile=cpu.pprof
goos: windows
goarch: amd64
pkg: jsontest
cpu: Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
BenchmarkMain
BenchmarkMain-4          1899802               577.3 ns/op           144 B/op          6 allocs/op
PASS
ok      jsontest        1.777s

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions