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

minor perf: update filter state method to reduce repeated hash searching #19609

Merged
merged 10 commits into from
Feb 10, 2022

Conversation

wbpcode
Copy link
Member

@wbpcode wbpcode commented Jan 19, 2022

Commit Message: minor perf: update filter state method to reduce repeated hash searching
Additional Description:

Minor optimization by simple code update. The fromFilterState will search FilterState multiple times. Some of these searches are duplicates. Try to reduce some unnecessary overhead by simplifying the api.

Before:

image

After:
image

Risk Level: Low.
Testing: N/A.
Docs Changes: N/A.
Release Notes: N/A.
Platform Specific Features: N/A.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks for the perf fix. A couple of API questions, thank you.

/wait

* An exception will be thrown if the data is not mutable.
*/
virtual Object* getDataMutableGeneric(absl::string_view data_name) PURE;

/**
* @param data_name the name of the data being probed.
* @return Whether data of the type and name specified exists in the
* data store.
*/
template <typename T> bool hasData(absl::string_view data_name) const {
Copy link
Member

Choose a reason for hiding this comment

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

Is this still used anywhere? Can it be removed to avoid using the pattern you removed in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is still used when we try to set some value to the filter state.

if(!filter_state.hasData<Type>(name)) {
  filter_state.setData(...);
}

Copy link
Member

Choose a reason for hiding this comment

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

Seems like this will also have the same double hash lookup issue? Maybe setData() should have a parameter about whether to set of it already exists? WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

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

get it.

Copy link
Member Author

Choose a reason for hiding this comment

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

It looks like it's more complicated than I thought it would be. The parent filter state and the mutable flag make it's hard to change the current hasData then setData code pattern.

Copy link
Member Author

Choose a reason for hiding this comment

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

@htuch Sounds reasonable to reserve two different API (getReadOnly/getMutable). But I am not sure if we should add special flag(StateType) for every filter state object.

Copy link
Member

Choose a reason for hiding this comment

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

I feel less strongly about the state type aspect. It seems like it could catch some kinds of errors, which all things being equal is a good thing. If there really is a genuine performance issue, we can probably eliminate, but I'd vote note to change it unless this is the cause of the observable performance loss.

Copy link
Member Author

Choose a reason for hiding this comment

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

@htuch StateType do not result in observable performance loss. But it makes the implementation of FilterState complex and there are some unsafe scenarios.

The following code is a common use of FilterState:

if(filter_state.hasData<Type>(name)) {
  auto state = filter_state.getDataMutable<Type>(...);
  // ......
}

But hasData will return true if there is a read only filter state object. Then the getDataMutable may throws un-catched exception.

However, the StateType can be used to avoid the FilterState Object being overwritten or modified. 🤔 So, there are both advantages and disadvantages.

Copy link
Member

Choose a reason for hiding this comment

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

The example you give is interesting. I think we should have a pattern such as getDataMutableOrNull and then use that instead of hasData; that seems the real unsafe thing. I'm not going to strongly advocate for this but I do see some advantage and fixing the above pattern in any case seems desirable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds great. I will try to solve it in a new PR. 🤔

envoy/stream_info/filter_state.h Outdated Show resolved Hide resolved
@wbpcode
Copy link
Member Author

wbpcode commented Feb 8, 2022

@mattklein123 @htuch Thanks for all your comments. Sorry for the delayed replies. I have just finished my long holiday.

@mattklein123
Copy link
Member

Can you check CI and I will take a look?

/wait

Signed-off-by: wbpcode <[email protected]>
@wbpcode
Copy link
Member Author

wbpcode commented Feb 9, 2022

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks this LGTM with small comments.

/wait

return *result;
template <typename T> const T* getDataReadOnly(absl::string_view data_name) const {
const auto* generic_result = getDataReadOnlyGeneric(data_name);
return generic_result == nullptr ? nullptr : dynamic_cast<const T*>(generic_result);
Copy link
Member

Choose a reason for hiding this comment

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

nit I think you can remove the conditional here and collapse this into a single line. dynamic_cast on nullptr is safe so you can just return that directly. Same below.

Copy link
Member Author

@wbpcode wbpcode Feb 10, 2022

Choose a reason for hiding this comment

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

get it.

return std::string();
}

auto typed_state = dynamic_cast<const StringAccessor*>(state);
Copy link
Member

Choose a reason for hiding this comment

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

Per other comment dynamic_cast on nullptr is OK so you can collapse this and make it simpler. Same elsewhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

get it.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks!

@mattklein123 mattklein123 merged commit e74999d into envoyproxy:main Feb 10, 2022
joshperry pushed a commit to joshperry/envoy that referenced this pull request Feb 13, 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
Development

Successfully merging this pull request may close these issues.

3 participants