Skip to content

Conversation

@Chriscbr
Copy link
Contributor

@Chriscbr Chriscbr commented Aug 27, 2023

Improve the performance of the constructs library by removing several branches in the library's hot paths and switching to some more performant operations.

On my laptop, the benchmark I used (shared in a gist here) takes about 5.0-5.3 seconds with the old version of constructs, and about 1.1-1.2 seconds with the new version of constructs.

Misc:

  • Removed an unused file in the test folder.
  • Added some files to npmignore to reduce the package's npm footprint.

* Components are separated by '/'.
*/
public get path(): string {
const components = this.scopes.filter(c => c.node.id).map(c => c.node.id);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calling filter generates one array, and calling map after creates another array. It should be slightly faster to create a single array and perform filtering inside a for loop.

throw new Error(`Cannot add children to "${this.path}" during synthesis`);
}

if (childName in this._children) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

From what I tested, array access is slightly faster than using the "in" operator

Comment on lines -426 to -428
if (!childName && this.id) {
throw new Error(`cannot add a nameless construct to the named scope: ${this.path}`);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think this if branch can get called. Here's my reasoning:

  1. addChild is only called if a non-null scope is passed to the Node constructor.
  2. if a non-null scope is passed to the Node constructor, and this.id has a falsey value (like undefined or an empty string), then an error will be thrown in the Node constructor before addChild is called.
  3. based on (1) and (2), when addChild is called, it's guaranteed that childName will not be a falsey value
  4. the if statement's body only executes if childName takes on a falsey value

I tried coming up with a test case that would actually throw this error but I don't think there's a way.

Comment on lines -432 to -434
if (Object.keys(this._children).length > 1 && Object.keys(this._children).filter(x => !x).length > 0) {
throw new Error('only a single construct is allowed in a scope if it has an empty name');
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I also don't think this branch can ever get called. Here was my reasoning:

  1. From my other comment, childName will never take on a falsey value (like an empty string).
  2. From (1), the line this._children[childName] = childl can never add falsey values as keys to this._children.
  3. There are no other lines of code that add new keys to this._children.
  4. Therefore, this._children will always have keys with truthy values, so Object.keys(this._children).filter(x => !x) can never have a length greater than 0.

@mrgrain
Copy link
Contributor

mrgrain commented Aug 29, 2023

image

Copy link
Contributor

@mrgrain mrgrain left a comment

Choose a reason for hiding this comment

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

Ha thanks for that!

@mergify mergify bot merged commit fdde3da into aws:10.x Aug 29, 2023
@Chriscbr Chriscbr deleted the perf branch August 29, 2023 18:45
Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

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

👍

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