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 copying of admission.Request #1291

Merged
merged 2 commits into from
May 27, 2021

Conversation

willbeason
Copy link
Member

What this PR does / why we need it:
The admission.Request type is 400 bytes, making it huge to pass by value
to functions. Each time this is passed to another function, the runtime
fully copies this object, often many times due to the function depth. In
general, we should avoid such unnecessary struct copying.

This PR reduces this copying (for example) by limiting several functions
to only ask for the subfield of admission.Request they need - the 3 bytes
referencing the Raw object byte slice. Other changes in this PR are
analogous.

I've only done the optimization where it added no complexity to the
call sites. For example, it would be valid to pass a pointer to the
admission.Request, but this could potentially have side effects as
the function would be able to mutate the input. In other cases, the
admission.Request would need to be replaced by more than one
argument so I've not done so (I can if desired).

@sozercan
Copy link
Member

sozercan commented May 7, 2021

@willbeason thanks for the PR! Looks like it needs DCO

@willbeason
Copy link
Member Author

There is a corresponding linter that identifies problems like these (hugeParam). The downside is that it's noisy so it isn't always appropriate (for the reasons I mentioned above).

Copy link
Member

@sozercan sozercan left a comment

Choose a reason for hiding this comment

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

LGTM

@shomron
Copy link
Contributor

shomron commented May 10, 2021

Thanks for the contribution! Is it possible to run before/after benchmarks in pkg/webhook to measure the effect of the change?

@willbeason
Copy link
Member Author

Thanks for the contribution! Is it possible to run before/after benchmarks in pkg/webhook to measure the effect of the change?

That's a good idea - I'll do that now and post back.

@willbeason
Copy link
Member Author

It looks like the difference between before/after is negligible at the scope of individual requests. Copying an admission.Request takes about 15ns:

(after change)

gatekeeper$ go test ./pkg/webhook -bench=BenchmarkValidateResourceName
goos: linux
goarch: amd64
pkg: github.com/open-policy-agent/gatekeeper/pkg/webhook
cpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz
BenchmarkValidateResourceName-12    	 3578606	       328.9 ns/op

(before change)

gatekeeper$ go test ./pkg/webhook -bench=BenchmarkValidateResourceName
goos: linux
goarch: amd64
pkg: github.com/open-policy-agent/gatekeeper/pkg/webhook
cpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz
BenchmarkValidateResourceName-12    	 3515958	       343.7 ns/op

Code I used for benchmarking:

func BenchmarkValidateResourceName(b *testing.B) {
	req := atypes.Request{}
	h := &validationHandler{}
	ctx := context.Background()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		h.validateConfigResource(ctx, req)
	}
}

@willbeason
Copy link
Member Author

The benchmarks run in milliseconds, so an 0.0001% change would be very difficult to measure directly:

gatekeeper$ go test ./pkg/webhook -bench=.
goos: linux
goarch: amd64
pkg: github.com/open-policy-agent/gatekeeper/pkg/webhook
cpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz
BenchmarkValidationHandler/psp:_100%_violations-12         	      56	  18723360 ns/op

@codecov-commenter
Copy link

codecov-commenter commented May 17, 2021

Codecov Report

Merging #1291 (2bfd99b) into master (43fd48e) will increase coverage by 0.10%.
The diff coverage is 28.57%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1291      +/-   ##
==========================================
+ Coverage   48.56%   48.67%   +0.10%     
==========================================
  Files          68       68              
  Lines        4890     4890              
==========================================
+ Hits         2375     2380       +5     
+ Misses       2164     2160       -4     
+ Partials      351      350       -1     
Flag Coverage Δ
unittests 48.67% <28.57%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
pkg/webhook/common.go 66.66% <ø> (ø)
pkg/webhook/policy.go 28.62% <0.00%> (ø)
pkg/webhook/mutation.go 17.64% <66.66%> (ø)
...onstrainttemplate/constrainttemplate_controller.go 57.92% <0.00%> (+1.61%) ⬆️

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 43fd48e...2bfd99b. Read the comment docs.

@maxsmythe
Copy link
Contributor

WDYT about using pointers to the request object?

I'm not against the change as-is, but using a pointer to the entire object might make it easier if we need to accommodate, say, more complex validation of the config resource.

@willbeason
Copy link
Member Author

WDYT about using pointers to the request object?

I'm not against the change as-is, but using a pointer to the entire object might make it easier if we need to accommodate, say, more complex validation of the config resource.

I think that's a pretty good argument to just use pointers. There's the chance of someone mutating the Request, but we shouldn't ever be trying to modify a Request in the first place.

If added to this PR, it would reduce copying further.

@maxsmythe
Copy link
Contributor

LMK when the pointer change has been made!

@willbeason willbeason force-pushed the hugeParam branch 6 times, most recently from 47dcdcd to 961fe14 Compare May 26, 2021 22:00
The admission.Request type is 400 bytes, making it huge to pass by value
to functions. Each time this is passed to another function, the runtime
fully copies this object, many times due to the function depth. In
general, we should avoid such unnecessary struct copying.

This PR makes our methods use a reference to admission.Request where
possible, greatly reducing copying.

Signed-off-by: Will Beason <willbeason@google.com>
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

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

LGTM

@maxsmythe maxsmythe merged commit c81772e into open-policy-agent:master May 27, 2021
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.

None yet

5 participants