Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[extend #1191] Unnecessary alloc for XML, JSON, JSONP #1199

Merged
merged 7 commits into from
Jan 14, 2019
Merged

[extend #1191] Unnecessary alloc for XML, JSON, JSONP #1199

merged 7 commits into from
Jan 14, 2019

Conversation

im-kulikov
Copy link
Contributor

@im-kulikov im-kulikov commented Oct 1, 2018

Implement methods for

  • JSON
  • JSONP
  • XML

fixes for tests
cc @vishr @ribice

Benchmark:

var testUser = user{1, "Jon Snow"}

func BenchmarkAllocJSONP(b *testing.B) {
	e := New()
	req := httptest.NewRequest(POST, "/", strings.NewReader(userJSON))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec).(*context)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		c.JSONP(http.StatusOK, "callback", testUser)
	}
}

func BenchmarkAllocJSON(b *testing.B) {
	e := New()
	req := httptest.NewRequest(POST, "/", strings.NewReader(userJSON))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec).(*context)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		c.JSON(http.StatusOK, testUser)
	}
}

func BenchmarkAllocXML(b *testing.B) {
	e := New()
	req := httptest.NewRequest(POST, "/", strings.NewReader(userJSON))
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec).(*context)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		c.XML(http.StatusOK, testUser)
	}
}

Result

# git checkout PR-branch
→ go test -test.v -test.run ^$ -test.bench ^BenchmarkAlloc* -count 10 > new.txt
# git checkout master-branch
→ go test -test.v -test.run ^$ -test.bench ^BenchmarkAlloc* -count 10 > old.txt

→ benchstat old.txt new.txt
name          old time/op    new time/op    delta
AllocJSONP-8    1.98µs ±17%    1.50µs ±12%  -24.11%  (p=0.000 n=10+9)
AllocJSON-8     1.82µs ±20%    1.73µs ± 6%     ~     (p=0.481 n=10+10)
AllocXML-8      4.27µs ±27%    4.27µs ±10%     ~     (p=0.549 n=10+9)

name          old alloc/op   new alloc/op   delta
AllocJSONP-8      193B ± 0%      162B ± 0%  -16.06%  (p=0.000 n=10+10)
AllocJSON-8       174B ± 0%      143B ± 0%  -17.82%  (p=0.000 n=10+10)
AllocXML-8      4.88kB ± 0%    4.77kB ± 0%   -2.30%  (p=0.019 n=6+8)

name          old allocs/op  new allocs/op  delta
AllocJSONP-8      5.00 ± 0%      4.00 ± 0%  -20.00%  (p=0.000 n=10+10)
AllocJSON-8       3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.000 n=10+10)
AllocXML-8        11.0 ± 0%      10.0 ± 0%   -9.09%  (p=0.000 n=10+10)

@codecov
Copy link

codecov bot commented Oct 1, 2018

Codecov Report

Merging #1199 into master will increase coverage by 0.25%.
The diff coverage is 82.92%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1199      +/-   ##
==========================================
+ Coverage   81.61%   81.86%   +0.25%     
==========================================
  Files          27       27              
  Lines        1931     1991      +60     
==========================================
+ Hits         1576     1630      +54     
- Misses        248      249       +1     
- Partials      107      112       +5
Impacted Files Coverage Δ
context.go 74.24% <82.92%> (-0.07%) ⬇️
echo.go 88.81% <0%> (+1.09%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ba1891b...c939bc1. Read the comment docs.

@im-kulikov
Copy link
Contributor Author

@alexaandru Hey, what do you think about it?

@alexaandru
Copy link
Contributor

I think in this particular case it would be overkill to have separate functions. The idea with "bool params is a code smell" is that it introduces complexity and makes code harder to understand, but it's not something set in stone, context always matter. Here we have very small functions, the "complexity" added is negligible and definitely smaller than the complexity of adding separate functions.

I did look into stdlib briefly and I did have a hard time finding functions that use bools as params, but I did find a couple (in the few minutes that I spent on it): https://golang.org/pkg/compress/gzip/#Reader.Multistream and https://golang.org/pkg/net/http/#Server.SetKeepAlivesEnabled

That being said... we could "cheat" a little ;) We could eliminate the bool param entirely and do the indent decision based on indent param alone: if not empty, then do the indent step, otherwise not.

@im-kulikov
Copy link
Contributor Author

im-kulikov commented Oct 9, 2018

Hm.. okay.. I’ll fix it


UPD: @alexaandru fixed

context.go Outdated
}

func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
return c.jsonBlob(code, i, true, indent)
return c.jsonBlob(code, i, indent)
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks risky. It works fine in JSON() where we control the indent ourselves, here however it messes things up :( If they want it pretty but with a blank indent (which I have no idea what it would do? just put each field on a separate line with no indent?) they will get it "not pretty". Should we return an error when the indent is blank for pretty? and also update the documentation to reflect that we expect a non blank indent to be provided for this function?

Yes, just checked, that's what it currently does, with a blank indent, it prints pretty with no indent:

{
"bar": 1,
"foo": 42
}

We can either revert back to using bool OR we can convert indent in jsonBlob() to be a pointer to string. That way, we don't check if it is blank, we check if it is nil. If nil == ugly json, if present (even if blank) == pretty json with that ident. That would allow us to keep the existing behavior where we accept even a blank indent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, you'll right

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed with indent pointer

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good to me 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Glad to hear.. waiting for @vishr review

@im-kulikov im-kulikov mentioned this pull request Oct 10, 2018
@ribice
Copy link
Contributor

ribice commented Oct 11, 2018

Looks good to me. Thanks for the benchmarks!

@im-kulikov
Copy link
Contributor Author

✌️Thx

@im-kulikov
Copy link
Contributor Author

im-kulikov commented Oct 15, 2018

@alexaandru / @vishr hi there! there is any chance to be merged?

@im-kulikov
Copy link
Contributor Author

@alexaandru / @vishr hi there! there is any chance to be merged?

@im-kulikov
Copy link
Contributor Author

im-kulikov commented Dec 9, 2018

@vishr hi there, it is not required and possible to be closed?


there is no reaction for more than two months

@im-kulikov im-kulikov closed this Dec 13, 2018
@im-kulikov im-kulikov deleted the unnecessary_allocs branch December 13, 2018 23:11
@im-kulikov
Copy link
Contributor Author

@vishr can I reopen PR?

@vishr
Copy link
Member

vishr commented Dec 18, 2018

It was a bot thing, please do it. It might take a while to get to it.

@im-kulikov im-kulikov restored the unnecessary_allocs branch December 18, 2018 18:18
@im-kulikov im-kulikov reopened this Dec 18, 2018
@im-kulikov
Copy link
Contributor Author

I just reopen, as I can see, all tests passed and has no conflicts with master..

@im-kulikov
Copy link
Contributor Author

@vishr ping?

@@ -206,6 +206,8 @@ const (
indexPage = "index.html"
)

var defaultIndent = " "
Copy link
Member

Choose a reason for hiding this comment

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

Can this be a const?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My mistake

@vishr vishr merged commit 62145fa into labstack:master Jan 14, 2019
@vishr
Copy link
Member

vishr commented Jan 14, 2019 via email

@im-kulikov
Copy link
Contributor Author

@vishr thx

@im-kulikov im-kulikov deleted the unnecessary_allocs branch January 14, 2019 18:15
@ribice
Copy link
Contributor

ribice commented Jan 14, 2019

Nice 👍

vishr added a commit that referenced this pull request Jan 14, 2019
Signed-off-by: Vishal Rana <vr@labstack.com>
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.

4 participants