Skip to content

Conversation

@rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented May 16, 2025

A large amount of stacks leads to a large body of metadata into the manifest.json file. The file can grow too large to be written to disk (>512MB), but even if it doesn't fail outright, serializing and writing and loading a large JSON file takes a lot of CPU time.

This PR splits the metadata for stacks off into a separate file which is written separately, moving it out of the hot path of working with the manifest.json file. On a tree of 256 stacks and ~40,000
constructs, this shaves off 5 seconds off of the total synthesis time.

Also in this PR: construct tree iteration was being done in a lot of places, with function
recursion and returning arrays. Moving this all into some functions that use generators. This improves performance only slightly, but it should improve memory usage by a whole lot for large construct trees.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@rix0rrr rix0rrr requested a review from a team as a code owner May 16, 2025 11:55
@aws-cdk-automation aws-cdk-automation requested a review from a team May 16, 2025 11:55
@github-actions github-actions bot added the p2 label May 16, 2025
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label May 16, 2025
A large amount of stacks leads to a large body of metadata into the
`manifest.json` file. The file can grow too large to be written to disk
(>512MB), but even if it doesn't fail outright, serializing and writing
and loading a large JSON file takes a lot of CPU time.

This PR splits the metadata for stacks off into a separate file which is
written separately, moving it out of the hot path of working with the
`manifest.json` file. On a tree of 256 stacks and ~40,000 constructs,
this shaves off 5 seconds off of the total synthesis time.
@rix0rrr rix0rrr force-pushed the huijbers/synth-perf branch from 27b76dd to 046eb38 Compare May 16, 2025 11:56
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

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

(This review is outdated)

@rix0rrr rix0rrr added the pr-linter/exempt-integ-test The PR linter will not require integ test changes label May 16, 2025
@aws-cdk-automation aws-cdk-automation dismissed their stale review May 16, 2025 11:59

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@rix0rrr rix0rrr changed the title fix: large amounts of stacks slow down synthesis fix: large amounts of stacks slows down synthesis May 16, 2025
* calls and accumulates into an array, both of which are much slower
* than this solution.
*/
export function* iterateDfsPreorder(root: IConstruct) {
Copy link
Contributor

Choose a reason for hiding this comment

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

[q]: preorder would be visiting left children before right one, which is not what this method does. Was that intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Preorder means parent before children, which this method does do.

import { IConstruct } from 'constructs';

/**
* Breadth-first iterator over the construct tree
Copy link
Contributor

Choose a reason for hiding this comment

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

You mean Depth-first?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, copy/paste-o. Thanks.

// Use a specialized queue data structure. Using `Array.shift()`
// has a huge performance penalty (difference on the order of
// ~50ms vs ~1s to iterate a large construct tree)
const queue: IConstruct[] = [root];
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be called stack (filo), a queue would be (fifo)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure.

@rix0rrr rix0rrr self-assigned this May 26, 2025
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: f04ec71
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

rix0rrr added a commit to aws/aws-cdk-cli that referenced this pull request Jun 3, 2025
When CDK apps grow extremely large (think 10-100 stacks, 1000-10000
constructs), all metadata together begins to exceed 512MB, the maximum
string size in NodeJS. People usually deal with this by disabling
metadata, but they shouldn't have to.

In addition, even for manifests that don't exceed 512MB the extremely
large size of the single JSON object slows down its writing and reading
every time, even if the metadata doesn't need to be accessed.

An effective solution is to write the metadata of an artifact to a
separate file. This PR introduces the ability for that into the Cloud
Assembly schema, and updates the CLI to read from both sources if
available.

Relates to aws/aws-cdk#34480.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution/core This is a PR that came from AWS. p2 pr-linter/exempt-integ-test The PR linter will not require integ test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants