Skip to content

Conversation

@camswords
Copy link
Collaborator

Summary

This pull request improves JSON unmarshalling performance by:

  • Inlining the Chromium error response into the response struct so that json.Unmarshal only needs to be called once per message, and
  • Replacing jsoniter with go-json as it is better maintained and seems to be more performant.

Benchmarks

The following test, benchmarked with the before and after versions of the code shows a 2.5x improvement on the sample data used. This is likely due to the reduced number of allocations.

goos: darwin
goarch: arm64
pkg: github.com/wirepair/gcd/v2
BenchmarkUnmarshalComputedStyleOld
BenchmarkUnmarshalComputedStyleOld-10    	   44449	     26598 ns/op	   10384 B/op	     551 allocs/op
BenchmarkUnmarshalComputedStyleNew
BenchmarkUnmarshalComputedStyleNew-10    	  111758	     10212 ns/op	    9760 B/op	     110 allocs/op

Test:

package gcd_test

import (
	"context"
	"github.com/wirepair/gcd/v2/gcdapi"
	"github.com/wirepair/gcd/v2/gcdmessage"
	"testing"
	"time"
)

func BenchmarkUnmarshalComputedStyleOld(b *testing.B) {
	var computedStyleJSON = []byte(`{"id":1015,"result":{"computedStyle":[{"name":"color","value":"rgb(255, 255, 255)"},{"name":"direction","value":"ltr"},{"name":"font-family","value":"\"Font Awesome 5 Free\""},{"name":"font-feature-settings","value":"normal"},{"name":"font-kerning","value":"auto"},{"name":"font-optical-sizing","value":"auto"},{"name":"font-palette","value":"normal"},{"name":"font-size","value":"22px"},{"name":"font-stretch","value":"100%"},{"name":"font-style","value":"normal"},{"name":"font-synthesis-small-caps","value":"auto"},{"name":"font-synthesis-style","value":"auto"},{"name":"font-synthesis-weight","value":"auto"},{"name":"font-variant-alternates","value":"normal"},{"name":"font-variant-caps","value":"normal"},{"name":"font-variant-east-asian","value":"normal"},{"name":"font-variant-ligatures","value":"normal"},{"name":"font-variant-numeric","value":"normal"},{"name":"font-variant-position","value":"normal"},{"name":"font-variation-settings","value":"normal"},{"name":"font-weight","value":"900"},{"name":"forced-color-adjust","value":"auto"},{"name":"text-orientation","value":"mixed"},{"name":"text-rendering","value":"auto"},{"name":"-webkit-font-smoothing","value":"antialiased"},{"name":"-webkit-locale","value":"\"en\""},{"name":"-webkit-text-orientation","value":"vertical-right"},{"name":"-webkit-writing-mode","value":"horizontal-tb"},{"name":"writing-mode","value":"horizontal-tb"},{"name":"zoom","value":"1"},{"name":"accent-color","value":"auto"},{"name":"align-content","value":"normal"},{"name":"align-items","value":"normal"},{"name":"align-self","value":"auto"},{"name":"alignment-baseline","value":"auto"},{"name":"all","value":""},{"name":"animation-composition","value":"replace"},{"name":"animation-delay","value":"0s"},{"name":"animation-direction","value":"normal"},{"name":"animation-duration","value":"0s"},{"name":"animation-fill-mode","value":"none"},{"name":"animation-iteration-count","value":"1"},{"name":"animation-name","value":"none"},{"name":"animation-play-state","value":"running"},{"name":"animation-range-end","value":"normal"},{"name":"animation-range-start","value":"normal"},{"name":"animation-timeline","value":"auto"},{"name":"animation-timing-function","value":"ease"},{"name":"app-region","value":"none"},{"name":"appearance","value":"none"},{"name":"aspect-ratio","value":"auto"},{"name":"backdrop-filter","value":"none"},{"name":"backface-visibility","value":"visible"},{"name":"background-attachment","value":"scroll"},{"name":"background-blend-mode","value":"normal"},{"name":"background-clip","value":"border-box"},{"name":"background-color","value":"rgba(0, 0, 0, 0)"},{"name":"background-image","value":"none"},{"name":"background-origin","value":"padding-box"},{"name":"background-position-x","value":"0%"},{"name":"background-position-y","value":"0%"},{"name":"background-repeat","value":"repeat"},{"name":"background-size","value":"auto"},{"name":"baseline-shift","value":"0px"},{"name":"baseline-source","value":"auto"},{"name":"block-size","value":"22px"},{"name":"border-block-end-color","value":"rgb(255, 255, 255)"},{"name":"border-block-end-style","value":"none"},{"name":"border-block-end-width","value":"0px"},{"name":"border-block-start-color","value":"rgb(255, 255, 255)"},{"name":"border-block-start-style","value":"none"},{"name":"border-block-start-width","value":"0px"},{"name":"border-bottom-color","value":"rgb(255, 255, 255)"},{"name":"border-bottom-left-radius","value":"0px"},{"name":"border-bottom-right-radius","value":"0px"},{"name":"border-bottom-style","value":"none"},{"name":"border-bottom-width","value":"0px"},{"name":"border-collapse","value":"separate"},{"name":"border-end-end-radius","value":"0px"},{"name":"border-end-start-radius","value":"0px"},{"name":"border-image-outset","value":"0"},{"name":"border-image-repeat","value":"stretch"},{"name":"border-image-slice","value":"100%"},{"name":"border-image-source","value":"none"},{"name":"border-image-width","value":"1"},{"name":"border-inline-end-color","value":"rgb(255, 255, 255)"},{"name":"border-inline-end-style","value":"none"},{"name":"border-inline-end-width","value":"0px"},{"name":"border-inline-start-color","value":"rgb(255, 255, 255)"},{"name":"border-inline-start-style","value":"none"},{"name":"border-inline-start-width","value":"0px"},{"name":"border-left-color","value":"rgb(255, 255, 255)"},{"name":"border-left-style","value":"none"},{"name":"border-left-width","value":"0px"},{"name":"border-right-color","value":"rgb(255, 255, 255)"},{"name":"border-right-style","value":"none"},{"name":"border-right-width","value":"0px"},{"name":"border-start-end-radius","value":"0px"},{"name":"border-start-start-radius","value":"0px"},{"name":"border-top-color","value":"rgb(255, 255, 255)"},{"name":"border-top-left-radius","value":"0px"},{"name":"border-top-right-radius","value":"0px"},{"name":"border-top-style","value":"none"},{"name":"border-top-width","value":"0px"},{"name":"bottom","value":"auto"},{"name":"box-shadow","value":"none"}]}}`)
	css := gcdapi.NewCSS(NewGCDFakeChromeTargeter(computedStyleJSON))
	ctx := context.Background()
	params := &gcdapi.CSSGetComputedStyleForNodeParams{NodeId: 1}

	results := make([][]*gcdapi.CSSCSSComputedStyleProperty, b.N)
	errors := make([]error, b.N)

	b.ReportAllocs()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		results[i], errors[i] = css.GetComputedStyleForNodeWithParams(ctx, params)
	}

	b.StopTimer()

	for i := 0; i < b.N; i++ {
		if errors[i] != nil {
			b.Fatalf("failed to parse message %v", errors[i].Error())
		}

		if len(results[i]) != 106 {
			b.Fatalf("expected 106 results, got %d", len(results[i]))
		}
	}
}

type GCDFakeChromeTargeter struct {
	message *gcdmessage.Message
}

func NewGCDFakeChromeTargeter(responseData []byte) *GCDFakeChromeTargeter {
	return &GCDFakeChromeTargeter{
		message: &gcdmessage.Message{
			ReplyCh: nil,
			Id:      0,
			Data:    responseData,
			Method:  "",
			Target:  nil,
		},
	}
}

func (t *GCDFakeChromeTargeter) GetId() int64 {
	return 0
}

func (t *GCDFakeChromeTargeter) GetApiTimeout() time.Duration {
	return 0
}

func (t *GCDFakeChromeTargeter) GetSendCh() chan *gcdmessage.Message {
	return nil
}

func (t *GCDFakeChromeTargeter) GetDoneCh() chan struct{} {
	return make(chan struct{})
}

func (t *GCDFakeChromeTargeter) SendCustomReturn(_ context.Context, _ *gcdmessage.ParamRequest) (*gcdmessage.Message, error) {
	return t.message, nil
}

func (t *GCDFakeChromeTargeter) SendDefaultRequest(_ context.Context, _ *gcdmessage.ParamRequest) (*gcdmessage.ChromeResponse, error) {
	return nil, nil
}

@camswords camswords requested a review from wirepair January 30, 2024 13:41
v2/gcd.go Outdated

import (
"context"
"encoding/json"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be "github.com/goccy/go-json" ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eeep! It should be, cheers. I'll fix it.

@wirepair wirepair merged commit 1102ae6 into wirepair:master Jan 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants