-
Notifications
You must be signed in to change notification settings - Fork 54
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
perf(validators): reduced GC pressure #170
Conversation
0f077a3
to
289f7a1
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #170 +/- ##
==========================================
+ Coverage 92.88% 93.30% +0.41%
==========================================
Files 22 23 +1
Lines 3277 3839 +562
==========================================
+ Hits 3044 3582 +538
- Misses 190 203 +13
- Partials 43 54 +11
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
289f7a1
to
35f689e
Compare
56bec80
to
cbbaf0b
Compare
This PR is a follow-up on go-openapi#169, which cames with innocuous changes, but already reduced the total number of allocations when validating a swagger spec. We reduce further the pressure on go's GC by pooling temporarily allocated objects: validators and results. When recursively allocating validators, calls to "Validate()" redeem to the pool the allocated validator. This means that a validator is usable only once. A similar approach is taken for `Result`s: upon merge, the merged result is redeemed to the pool. Eventually, temporarily allocated `spec.Schema`s are also pooled. In order not to break existing interfaces, this is enabled by default only when validating a spec (`Spec()`) or when using `AgainstSchema()`. Another option at the spec level allows for skipping the gathering of schemas into the result ("schemata"): these schemas must be cloned to remain valid after their parent is redeemed to the pool. Comment on the benchmark: CPU profiling shows that about 30% of the CPU time is spent managing garbage. Memory profiling shows that our benchmark (validating the k8s API spec) goes down from 25M allocated objects down to ~ 17M (go-openapi#169 went down from 60M to 25M). The `Validate` method generates only ~ 5M of those, out of which ~ 4M are caused by the schema unmarshaling & expansion and 1M by string allocations for the validator "path". Unfortunately, classic string interning methods don't work well with this dynamic "path", so I leave it there. Integration tests (go-swagger/go-swagger#3064) show a significant improvement when running go-swagger validate in codegen. * contributes: go-swagger/go-swagger#2649 Further improvements would most likely come from optimizing the validation of defaults and examples (which amount for 2M allocs). Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
cbbaf0b
to
44a8ced
Compare
Kubernetes uses an approach where they use an embedded memory allocator on objects that go to and from json frequently. |
|
* onboards perf improvements in validate from go-openapi/validate#170 Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
* onboards perf improvements in validate from go-openapi/validate#170 Signed-off-by: Frédéric BIDON <fredbi@yahoo.com>
This PR is a follow-up on #169, which cames with innocuous changes, but already
reduced the total number of allocations when validating a swagger spec.
We reduce further the pressure on go's GC by pooling temporarily
allocated objects: validators and results.
When recursively allocating validators, calls to "Validate()" redeem to the pool the allocated
validator. This means that a validator is usable only once.
A similar approach is taken for
Result
s: upon merge, the merged resultis redeemed to the pool.
Eventually, temporarily allocated
spec.Schema
s are also pooled.In order not to break existing interfaces, this is enabled by default
only when validating a spec (
Spec()
) or when usingAgainstSchema()
.Another option at the spec level allows for skipping the gathering of schemas
into the result ("schemata"): these schemas must be cloned to remain
valid after their parent is redeemed to the pool.
Comment on the benchmark:
CPU profiling shows that about 30% of the CPU time is spent managing
garbage.
Memory profiling shows that our benchmark (validating the k8s API spec) goes
down from 25M allocated objects down to ~ 17M (#169 went down from 60M to 25M).
The
Validate
method generates only ~ 5M of those, out of which~ 4M are caused by the schema unmarshaling & expansion and 1M by string
allocations for the validator "path".
Unfortunately, classic string interning methods don't work well with this dynamic "path",
so I leave it there.
Integration tests (go-swagger/go-swagger#3064)
show a significant improvement when running go-swagger validate in codegen.
Further improvements would most likely come from optimizing the
validation of defaults and examples (which amount for 2M allocs).
Signed-off-by: Frederic BIDON fredbi@yahoo.com