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

302 at compound key errorpath optimization #4

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

karthikreddy09
Copy link
Member

RFC for optimizing error path for AtCompoundKey, with design options and performance analysis.

@karthikreddy09 karthikreddy09 requested a review from a team October 10, 2018 12:29

## Motivation

Using AtCoumpoundKey with non-existent keys produces an exception. If the API is used extensively, the application performace is degraded as reported by a team at Mathworks Inc. Users prefer not to pay for the cost of exception handling in case a compound key is not found in the AnyMap.
Copy link
Contributor

Choose a reason for hiding this comment

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

AtCoumpoundKey -> AtCompoundKey


## Description of the Problem

AnyMap provides a convinience API to retrieve objects from the map using compound keys with dot notation. The API is very nifty and saves users from writing redundant code to parse through the nested maps. However, the performance of the error path is significantly higher than for the happy path in this API. This have resulted in performace degradation in some use cases. The performace hit is due to C++ exception handling mechanism. Although AtCompoundKey is similar to the STL map's `at` API, STL maps have other methods such as the `find` which can be used to efficiently access an element in the map without having to deal with the exceptions.
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo convinience

text/0000-atcompoundkey-error-path-optimization.md Outdated Show resolved Hide resolved
Add an overload with the following signature:

```
Any AtCompoundKey(const std::string& key, Any&& defaultvalue) const;
Copy link
Contributor

@ksubramz ksubramz Oct 10, 2018

Choose a reason for hiding this comment

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

The issue here is that the clients can't create a default "sentinel" Any value and keep using it for further AtCompoundKey calls i.e. under this scenario, the following use case isn't possible

Any sentinel = std::string("sentinel");
auto anyval = myanymap.AtCompoundKey("foo.bar.baz", sentinel);
if (anyval == sentinel) {...} else {...}
auto anyval2 = myanymap.AtCompoundKey("foo.bar.doe", sentinel);
...

The user is forced to do the following which maybe a pain-point

Any sentinel = std::string("sentinel");
auto anyval = myanymap.AtCompoundKey("foo.bar.baz", std::move(sentinel));
if (anyval == std::string("sentinel") {...} else {...}
Any sentinel2 = std::string("sentinel");
auto anyval2 = myanymap.AtCompoundKey("foo.bar.doe", std::move(sentinel2));
  • a solution is to simply pass the default by value?
  • another is to have 2 overloads
    • one with const Any& default
    • delete the move variant i.e. Any AtCompoundKey(const std::string& key, Any&& defaultvalue) const = delete; ? (Note: only if we think the users won't prefer to pass temporary Anys as a default value)

Copy link
Member Author

Choose a reason for hiding this comment

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

pass by value seems simpler. Not sure if the users won't want to pass a temporary.

Copy link
Member

@jeffdiclemente jeffdiclemente left a comment

Choose a reason for hiding this comment

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

The graphs are great!
I agree that option 2.1 seems like the best way to go.

text/0000-atcompoundkey-error-path-optimization.md Outdated Show resolved Hide resolved
text/0000-atcompoundkey-error-path-optimization.md Outdated Show resolved Hide resolved
text/0000-atcompoundkey-error-path-optimization.md Outdated Show resolved Hide resolved
text/0000-atcompoundkey-error-path-optimization.md Outdated Show resolved Hide resolved
Signed-off-by: The Mathworks Inc <[email protected]>
Copy link
Member

@saschazelzer saschazelzer left a comment

Choose a reason for hiding this comment

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

I would appreciate a close look at the pros / cons of the JSON approach. Also, backwards compatibility is not an issue in opinion, since we are moving to 4.0 with other breaking changes anyway.


### Cons
* Happy path has a slight performance decrease due to the use of 'find' API instead of the 'at' API
* Although the API returns a const reference, the user could add back a non-const version by const_cast'ing the returned ref, which will break every subsequent call. Infact the current non-const API does exactly this, which is ikky.
Copy link
Member

Choose a reason for hiding this comment

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

I do not think that this is a real concern. const-casting will always be fishy. Another example is #define private public before including third-party headers and then accessing their private members. Just because users can do this, we do not stop using classes.

* Users can use the JSON object to write their custom parsing functions or pass around JSON objects in their code

### Cons
* Users have to parse through the JSON tree to retrieve the values.
Copy link
Member

Choose a reason for hiding this comment

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

I do not understand how this is substantially different from the AnyMap API. In JSON, there is actually a even better way of accessing elements in a hierarchy directly, RFC 6901. This is supported by at least rapidjson and nlohmann JSON.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is interesting. Thanks for the link, @saschazelzer!


### Cons
* Users have to parse through the JSON tree to retrieve the values.
* The team currently using AtCompoundKey does not like this option. They do not want to deal with the any_cast at each level of the map
Copy link
Member

Choose a reason for hiding this comment

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

It looks like the opinion is based on wrong assumptions or an incomplete picture of available JSON APIs. For example, another benefit of existing JSON libraries is their support for implicit conversions, which any_cast does not support.

Copy link
Member Author

@karthikreddy09 karthikreddy09 Oct 19, 2018

Choose a reason for hiding this comment

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

On a cursory look. rapidjson's GenericValue API has methods to query type, existence and extract value. Its not clear from the documentation what will happen if I call the GetArray method and the type is not an array. The implementation of the Get methods use RAPIDJSON_ASSERT which is a no-op in production. There is an option to override the MACRO to throw.

I will follow up with the client team about this option.

Copy link
Member

Choose a reason for hiding this comment

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

Such conversions will typically throw or abort. I was rather referring to code like
int x = json["x"] or double x = json["x"] which would both work if "x" is convertible to int and double (rapidjson or nlohmann JSON).


## Unresolved questions

> Will we ever support null values in bundle's manifest.json file?
Copy link
Member

@saschazelzer saschazelzer Oct 18, 2018

Choose a reason for hiding this comment

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

It doesn't look like it is important enough at this time.

* It is not clear how a null value from a manifest file is treated. specifying "null" is legal in JSON. Current implementation of bundle metadata parser ignores the entries with null value. However, we cannot assume this will not change in the future.
* The information regarding the error conditions is lost.

## Option 2.1 (Preferred) - Add an overload with a default value parameter
Copy link
Member

Choose a reason for hiding this comment

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

If we finally decide against the JSON API approach, I think a combination of 1. and 2.1. would make sense. Basically like the std::optional API and providing a const& Any AtCompoundKey(const std::string&) const as well as a Any AtCompoundKeyOr(const std::string&, Any) const function.

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.

4 participants