Skip to content

Improve performance of generated enum methods #2693

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

Merged
merged 3 commits into from
Sep 8, 2021

Conversation

Bennett-Lynch
Copy link
Contributor

Motivation

Generated enums use a standard fromValue method to resolve a string
value (usually received on the wire) to the corresponding enum. The
existing implementation is not optimal for a few reasons:

  1. It calls Enum#values(), which must allocate a new array every time
  2. It iterates the entire array with O(N) complexity

The generated knownValues follows a similar pattern, plus it does not
take advantage of EnumSet, which is typically faster than HashSet.

These are minor optimization concerns, however many code paths
repeatedly call fromValue() (as opposed to caching it).

Modifications

  • For each generated enum, store a value map which maps the string value
    to the corresponding enum constant value. Use this map for fromValue.
  • Use an EnumSet for knownValues.
  • Create new CollectionUtils.index() & EnumUtils.index() methods to
    facilitate the common use case of constructing a unique index lookup map

Result

  • fromValue changes from O(N) to O(1)
  • Minor increase in memory overhead from storing a static map, but
    reduced allocation from creating new arrays every method call

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed
  • A short description of the change has been added to the CHANGELOG
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

## Motivation

Generated enums use a standard `fromValue` method to resolve a string
value (usually received on the wire) to the corresponding enum. The
existing implementation is not optimal for a few reasons:

1. It calls `Enum#values()`, which must allocate a new array every time
2. It iterates the entire array with O(N) complexity

The generated `knownValues` follows a similar pattern, plus it does not
take advantage of `EnumSet`, which is typically faster than HashSet.

These are minor optimization concerns, however many code paths
repeatedly call `fromValue()` (as opposed to caching it).

## Modifications

* For each generated enum, store a value map which maps the string value
to the corresponding enum constant value. Use this map for `fromValue`.
* Use an EnumSet for `knownValues`.
* Create new `CollectionUtils.index()` & `EnumUtils.index()` methods to
facilitate the common use case of constructing a unique index lookup map

## Result

* `fromValue` changes from O(N) to O(1)
* Minor increase in memory overhead from storing a static map, but
reduced allocation from creating new arrays every method call
for (V value : values) {
K index = indexFunction.apply(value);
V prev = map.put(index, value);
Validate.isNull(prev, "No duplicate indices allowed but both %s and %s have the same index: %s",
Copy link
Contributor

Choose a reason for hiding this comment

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

Query : Since we are indexing to unique Converted type should that be reflected in the function name ?

In some case in future I might even want to index duplicate value in where I would expect Map<K, List> might have difficulty to use the same function name in this class

Copy link
Contributor Author

@Bennett-Lynch Bennett-Lynch Sep 3, 2021

Choose a reason for hiding this comment

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

Good point/question.

My thinking is that indexing like this would be the common/standard use case, where users expect unique indices, and if we wanted to extend this to something like multi-map support, then that new function name would be specialized to differentiate. E.g., index vs indexMulti, or similar.

However, since the current function can throw, then perhaps there is an argument for giving this one more explicit naming. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed index to uniqueIndex.

Bennett Lynch and others added 2 commits September 3, 2021 14:28
## Motivation

Generated enums use a standard `fromValue` method to resolve a string
value (usually received on the wire) to the corresponding enum. The
existing implementation is not optimal for a few reasons:

1. It calls `Enum#values()`, which must allocate a new array every time
2. It iterates the entire array with O(N) complexity

The generated `knownValues` follows a similar pattern, plus it does not
take advantage of `EnumSet`, which is typically faster than HashSet.

These are minor optimization concerns, however many code paths
repeatedly call `fromValue()` (as opposed to caching it).

## Modifications

* For each generated enum, store a value map which maps the string value
to the corresponding enum constant value. Use this map for `fromValue`.
* Use an EnumSet for `knownValues`.
* Create new `CollectionUtils.index()` & `EnumUtils.index()` methods to
facilitate the common use case of constructing a unique index lookup map

## Result

* `fromValue` changes from O(N) to O(1)
* Minor increase in memory overhead from storing a static map, but
reduced allocation from creating new arrays every method call
@sonarqubecloud
Copy link

sonarqubecloud bot commented Sep 8, 2021

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

@Bennett-Lynch Bennett-Lynch merged commit 1c347c8 into aws:master Sep 8, 2021
aws-sdk-java-automation added a commit that referenced this pull request Sep 15, 2023
…43782f0c0

Pull request: release <- staging/75cecad7-0108-47c2-889d-fa443782f0c0
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.

2 participants