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

Reduce memory footprint by reusing buffers #229

Closed
wants to merge 2 commits into from

Conversation

cezarsa
Copy link

@cezarsa cezarsa commented Feb 26, 2016

This PR adds some benchmarks for Collection.Insert() and changes mongoSocket.Query() and addBSON() to reuse allocated []byte buffers by getting and putting then into a sync.Pool.

Also the function MarshalBuffer was added to the bson package. It behaves in the exact same way as Marshal but instead of allocating a []byte buffer it receives an already existing buffer.

I came upon these changes after profiling a real world application that inserts a lot of documents simultaneously.

The added benchmarks show a really nice decrease in memory footprint specially when large messages are being sent to MongoDB, as is the case of inserting multiple documents at once:

$ benchcmp before.txt after.txt
benchmark                     old ns/op     new ns/op     delta
BenchmarkInsertSingle-4       94191         90779         -3.62%
BenchmarkInsertMultiple-4     1076423       937569        -12.90%

benchmark                     old allocs     new allocs     delta
BenchmarkInsertSingle-4       50             46             -8.00%
BenchmarkInsertMultiple-4     456            242            -46.93%

benchmark                     old bytes     new bytes     delta
BenchmarkInsertSingle-4       2472          1320          -46.60%
BenchmarkInsertMultiple-4     191180        29228         -84.71%

I did't use gocheck for the benchmarks because it was returning some weird numbers. I'm not sure whether I did something wrong but these are the numbers for the exact same code only adapting it to use gocheck:

$ go test -check.f BenchmarkInsert -check.b -check.bmem
PASS: session_test.go:4191: S.BenchmarkInsertMultiple        500       2627615 ns/op      813412 B/op       2612 allocs/op
PASS: session_test.go:4175: S.BenchmarkInsertSingle     5000        265921 ns/op       16268 B/op        214 allocs/op
OK: 2 passed
PASS
ok      gopkg.in/mgo.v2 3.462s

Compared to the use of native benchmarks:

$ go test -check.f xxx -test.bench BenchmarkInsert -test.benchmem
OK: 0 passed
PASS
BenchmarkInsertSingle-4        20000         99943 ns/op        1384 B/op         48 allocs/op
BenchmarkInsertMultiple-4       2000       1101579 ns/op       32590 B/op        343 allocs/op
ok      gopkg.in/mgo.v2 5.449s

Maybe I did something wrong and I'm open to work on it further if you have any tips.

This commit changes mongoSocket.Query to reuse allocated []byte buffers
by getting and putting then into a sync.Pool.

Also the function MarshalBuffer was added to the bson package and the
addBSON function now uses it. It behaves in the exact same way to
Marshal but instead of allocating a []byte buffer it receives an already
existing buffer.

Benchmarks show a really nice decrease in memory footprint specially
when large messages are being sent to MongoDB, as is the case of
inserting multiple documents at once.

$ benchcmp before.txt after.txt
benchmark                     old ns/op     new ns/op     delta
BenchmarkInsertSingle-4       94191         90779         -3.62%
BenchmarkInsertMultiple-4     1076423       937569        -12.90%

benchmark                     old allocs     new allocs     delta
BenchmarkInsertSingle-4       50             46             -8.00%
BenchmarkInsertMultiple-4     456            242            -46.93%

benchmark                     old bytes     new bytes     delta
BenchmarkInsertSingle-4       2472          1320          -46.60%
BenchmarkInsertMultiple-4     191180        29228         -84.71%
@cezarsa
Copy link
Author

cezarsa commented Feb 27, 2016

Today I figured a way to simplify the code and improve even more the benchmarks. I've already updated the commits and the benchmark result comparison on the original comment.

@niemeyer
Copy link
Contributor

niemeyer commented Jun 8, 2016

That's nice. I've been meaning to look into buffer reuse, but always thought about the harder case which is unmarshaling. This is a much easier win.

Will need a few tweaks since we should expose that via an interface such as bson.NewEncoder instead of MarshalBuffer, but I can tweak that on my end.

wpjunior pushed a commit to wpjunior/mgo that referenced this pull request Aug 12, 2018
* Add 3.6 user authenticationRestrictions

* Add struct-field comment

* Add struct-field comment go-mgo#2

* Add struct-field comment go-mgo#3

* Add documentation link

* Fix comment

* Fix comment go-mgo#2

* add to README.md

* add to README.md go-mgo#2

* add to README.md go-mgo#3

* Add positive/negative authentication restrictions user test

* Use denyUser for negative test

* Correct message

* Fix error match

* Fix close on nil/closed session

* Simplify test, last change :)

* Simplify test, last change :) go-mgo#2

* Simplify test, last change :) go-mgo#3

* Fix := error
@cezarsa cezarsa closed this Jan 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants