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

Any filter optimization #7205

Merged

Conversation

Cali0707
Copy link
Member

@Cali0707 Cali0707 commented Aug 24, 2023

Fixes #7203

Proposed Changes

  • Dynamically reorder the any filter fields

Release Note

The Any filter now dynamically optimizes the order of nested filters for optimal performance.

Results

Before the optimization:

go test -bench=BenchmarkAnyFilter -benchtime=15s . -v
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8         	25391394	      837.5 ns/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8           	22175893	      887.9 ns/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8     	7598865	     2416 ns/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8   	19496820	      880.2 ns/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	81.362s

After the optimizations:

go test -bench=BenchmarkAnyFilter -benchtime=15s . -v
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8         	21293139	      857.1 ns/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8           	16824603	     1066 ns/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8     	16708528	     1063 ns/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8   	16840482	     1069 ns/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	76.067s

@knative-prow knative-prow bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Aug 24, 2023
@knative-prow knative-prow bot requested review from lionelvillard and matzew August 24, 2023 21:03
@Cali0707
Copy link
Member Author

/cc @pierDipi @matzew
Do you think this performance tradeoff is reasonable? If it is I can work on further improving the optimization proof of concept on this branch

@knative-prow knative-prow bot requested a review from pierDipi August 24, 2023 21:04
@codecov
Copy link

codecov bot commented Aug 24, 2023

Codecov Report

Attention: 11 lines in your changes are missing coverage. Please review.

Comparison is base (3dfc2ea) 77.54% compared to head (74118e6) 77.53%.
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7205      +/-   ##
==========================================
- Coverage   77.54%   77.53%   -0.02%     
==========================================
  Files         250      250              
  Lines       13529    13566      +37     
==========================================
+ Hits        10491    10518      +27     
- Misses       2514     2523       +9     
- Partials      524      525       +1     
Files Coverage Δ
pkg/eventfilter/subscriptionsapi/any_filter.go 78.00% <74.41%> (-14.31%) ⬇️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Cali0707
Copy link
Member Author

/hold
I just realized a logic mistake, will fix it tomorrow and provide updated benchmarks

@knative-prow knative-prow bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Aug 24, 2023
@pierDipi
Copy link
Member

pierDipi commented Aug 25, 2023

Can you also show the memory consumption -benchmem?

@Cali0707
Copy link
Member Author

@pierDipi here is the benchmarks after the logic fix, and including the memory used for creating the filter and running the filter:

Without Optimization

go test -bench=BenchmarkAnyFilter -benchtime=15s -benchmem ./benchmarks
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8         	202792717	       95.71 ns/op	     40 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8              	25106172	      913.3 ns/op	    424 B/op	      8 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8           	139472294	      130.4 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                	20394402	      871.5 ns/op	    424 B/op	      8 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8     	131053297	      141.4 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8          	7209354	     2339 ns/op	    976 B/op	     21 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8   	141747772	      132.0 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8        	24671895	      854.6 ns/op	    424 B/op	      8 allocs/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	207.089s

With Optimization

go test -bench=BenchmarkAnyFilter -benchtime=15s -benchmem ./benchmarks 
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8         	265946888	       70.85 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8              	21527318	      995.5 ns/op	    464 B/op	     10 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8           	173197423	      104.0 ns/op	    128 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                	17348818	     1056 ns/op	    464 B/op	     10 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8     	173441316	      103.9 ns/op	    128 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8          	17277901	     1057 ns/op	    464 B/op	     10 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8   	173314597	      103.9 ns/op	    128 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8        	17353970	     1056 ns/op	    464 B/op	     10 allocs/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	191.571s

@Cali0707 Cali0707 requested a review from pierDipi August 25, 2023 14:35
Signed-off-by: Calum Murray <[email protected]>
@knative-prow knative-prow bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Aug 25, 2023
@Cali0707 Cali0707 marked this pull request as draft August 25, 2023 19:58
@knative-prow knative-prow bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 25, 2023
@Cali0707 Cali0707 changed the title Any filter optimization [WIP]: Any filter optimization Aug 25, 2023
@Cali0707
Copy link
Member Author

Cali0707 commented Aug 25, 2023

Note: with my most recent commit, I introduced a Done method to the Filter interface. This makes sense in the context of having long-running filters, which is the idea behind why this optimization works. Upon looking more closely at where the filters are used, it seems like every time an event is filtered, a new set of filters is created and then destroyed. I think we should probably refactor the code to just make the filters once and then reuse them over time, but that will likely have impacts on things such as memory.

I've opened an issue for this here: #7210

@Cali0707
Copy link
Member Author

Cali0707 commented Aug 25, 2023

The results of these optimizations are:

Without Optimization

go test -bench=BenchmarkAnyFilter -benchtime=15s -benchmem -count=1 ./benchmarks
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8         	195075799	       97.22 ns/op	     40 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8              	26852019	      877.3 ns/op	    424 B/op	      8 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8           	151923921	      118.9 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                	24518143	      905.8 ns/op	    424 B/op	      8 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8     	126858039	      131.0 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8          	8284282	     2317 ns/op	    976 B/op	     21 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8   	137686453	      119.0 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8        	17395599	      901.6 ns/op	    424 B/op	      8 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters-8         	180996684	      116.6 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters-8              	9570231	     1975 ns/op	    876 B/op	     19 allocs/op
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8         	179665990	      115.6 ns/op	     72 B/op	      2 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8              	8789848	     2125 ns/op	    876 B/op	     19 allocs/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	307.679s

With Optimization

go test -bench=BenchmarkAnyFilter -benchtime=15s -benchmem -count=1 ./benchmarks
goos: linux
goarch: amd64
pkg: knative.dev/eventing/pkg/eventfilter/benchmarks
cpu: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_with_exact_filter_test-8         	32064643	      559.1 ns/op	    296 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8                           	22674676	      954.1 ns/op	    400 B/op	      7 allocs/op
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_match_all_subfilters-8           	22712284	      708.0 ns/op	    352 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                             	19123402	      941.9 ns/op	    400 B/op	      7 allocs/op
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_no_1_match_at_end_of_array-8     	25415569	      708.8 ns/op	    352 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8                       	19043733	      942.7 ns/op	    400 B/op	      7 allocs/op
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_no_1_match_at_start_of_array-8   	25238700	      712.1 ns/op	    352 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8                     	18949026	      944.1 ns/op	    400 B/op	      7 allocs/op
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_2_events_match_2_different_filters-8         	25721706	      696.5 ns/op	    320 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters-8                           	12370842	     1481 ns/op	    532 B/op	     10 allocs/op
BenchmarkAnyFilter/Creation_and_teardown:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8         	25303110	      711.1 ns/op	    352 B/op	      5 allocs/op
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8                           	12046114	     1472 ns/op	    532 B/op	     10 allocs/op
PASS
ok  	knative.dev/eventing/pkg/eventfilter/benchmarks	228.352s

@Cali0707 Cali0707 changed the title [WIP]: Any filter optimization Any filter optimization Aug 28, 2023
@Cali0707 Cali0707 marked this pull request as ready for review August 28, 2023 15:14
@knative-prow knative-prow bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 28, 2023
@knative-prow knative-prow bot requested review from creydr and odacremolbap August 28, 2023 15:14
@Cali0707
Copy link
Member Author

@pierDipi @matzew I marked this PR as ready to review as I think the optimizations I made are ready to be looked at, but there is probably a bit of work to do refactoring places where the filters are used before this is merged, so PR is on hold. Lmk if the performance tradeoffs here make sense to you, and I will work on those refactorings so that this can be merged!

@Cali0707
Copy link
Member Author

Cali0707 commented Sep 14, 2023

Here is an updated comparison:

benchmark                                                                                                                   old ns/op     new ns/op     delta
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8                                                            97.2          559           +475.09%
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8                                                                 877           954           +8.75%
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8                                                              119           708           +495.46%
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                                                                   906           942           +3.99%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8                                                        131           709           +441.07%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8                                                             2317          943           -59.31%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8                                                      119           712           +498.40%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8                                                           902           944           +4.71%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters-8                                                117           696           +497.34%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters-8                                                     1975          1481          -25.01%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8     116           711           +515.14%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8          2125          1472          -30.73%

benchmark                                                                                                                   old allocs     new allocs     delta
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8                                                            2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8                                                                 8              7              -12.50%
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8                                                              2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                                                                   8              7              -12.50%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8                                                        2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8                                                             21             7              -66.67%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8                                                      2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8                                                           8              7              -12.50%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters-8                                                2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters-8                                                     19             10             -47.37%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8     2              5              +150.00%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8          19             10             -47.37%

benchmark                                                                                                                   old bytes     new bytes     delta
BenchmarkAnyFilter/Creation:_Any_filter_with_exact_filter_test-8                                                            40            296           +640.00%
BenchmarkAnyFilter/Run:_Any_filter_with_exact_filter_test-8                                                                 424           400           -5.66%
BenchmarkAnyFilter/Creation:_Any_filter_match_all_subfilters-8                                                              72            352           +388.89%
BenchmarkAnyFilter/Run:_Any_filter_match_all_subfilters-8                                                                   424           400           -5.66%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_end_of_array-8                                                        72            352           +388.89%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_end_of_array-8                                                             976           400           -59.02%
BenchmarkAnyFilter/Creation:_Any_filter_no_1_match_at_start_of_array-8                                                      72            352           +388.89%
BenchmarkAnyFilter/Run:_Any_filter_no_1_match_at_start_of_array-8                                                           424           400           -5.66%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters-8                                                72            320           +344.44%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters-8                                                     876           532           -39.27%
BenchmarkAnyFilter/Creation:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8     72            352           +388.89%
BenchmarkAnyFilter/Run:_Any_filter_2_events_match_2_different_filters,_one_filter_in_front_which_matches_neither-8          876           532           -39.27%

Note: the creation comparison is not one to one here, as in the new version of the code it is actually both creating and deleting the filter (as each creation creates a goroutine in the new version).

Given that creation will only happen once (after #7213 is merged), I think we should move forwards with this option.
/cc @aliok @creydr @pierDipi @matzew

@knative-prow-robot knative-prow-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 23, 2023
Signed-off-by: Calum Murray <[email protected]>
@knative-prow-robot knative-prow-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 25, 2023
@Cali0707
Copy link
Member Author

/unhold
/cc @pierDipi @creydr

I think this PR is ready to go

@knative-prow knative-prow bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 25, 2023
Signed-off-by: Calum Murray <[email protected]>
Copy link
Member

@pierDipi pierDipi left a comment

Choose a reason for hiding this comment

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

/lgtm
/approve

@knative-prow knative-prow bot added the lgtm Indicates that a PR is ready to be merged. label Sep 29, 2023
@knative-prow
Copy link

knative-prow bot commented Sep 29, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Cali0707, pierDipi

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow knative-prow bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 29, 2023
@knative-prow knative-prow bot merged commit 3b1465a into knative:main Sep 29, 2023
25 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New Event Filtering: Investigate dynamic array ordering optimization for event filters
3 participants