Skip to content

Reduce memory footprint of Node classes#2790

Open
KuechA wants to merge 14 commits into
mainfrom
ak/slim-expr
Open

Reduce memory footprint of Node classes#2790
KuechA wants to merge 14 commits into
mainfrom
ak/slim-expr

Conversation

@KuechA

@KuechA KuechA commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

We allocate a significant amount of memory in the Node classes. Partially because we have a lot of attributes (which may not even be used), partially due to inefficient datastructures. This PR implements a couple of things:

  • It extracts locals from all Expressions and adds it where necessary.
  • It changes the EdgeList and EdgeSet implementations as they often hold a single value but are always a List/Set.
  • Lazy initialization of unused properties in Nodes and Edges (e.g. additionalProblems, assumptions).
  • Reuse name as code for References which is the case most of the time
  • Minor improvements in Name class
  • Identity-based management in EdgeList and EdgeSet to speed up the runtime

This seems to have a positive impact - if my tests were correct this may reduce it from ~10 to ~8.5 GB for a 300k LOC project and also helped to reduce the run-time from ~20min to ~16-18min.

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.31356% with 159 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.04%. Comparing base (2a661f6) to head (70c483b).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ofer/aisec/cpg/graph/edges/collections/EdgeList.kt 68.04% 20 Missing and 11 partials ⚠️
...hofer/aisec/cpg/graph/edges/collections/EdgeSet.kt 76.66% 14 Missing and 7 partials ⚠️
.../graph/edges/collections/MirroredEdgeCollection.kt 37.50% 8 Missing and 2 partials ⚠️
...isec/cpg/graph/edges/collections/EdgeCollection.kt 0.00% 9 Missing ⚠️
.../cpg/graph/edges/collections/CompactEdgeStorage.kt 65.21% 3 Missing and 5 partials ⚠️
...c/cpg/graph/edges/collections/EdgeSingletonList.kt 42.85% 3 Missing and 5 partials ⚠️
.../fraunhofer/aisec/cpg/graph/expressions/DoWhile.kt 33.33% 7 Missing and 1 partial ⚠️
...hofer/aisec/cpg/graph/expressions/Comprehension.kt 41.66% 5 Missing and 2 partials ⚠️
...n/de/fraunhofer/aisec/cpg/graph/expressions/For.kt 36.36% 7 Missing ⚠️
.../fraunhofer/aisec/cpg/graph/expressions/ForEach.kt 46.15% 5 Missing and 2 partials ⚠️
... and 12 more

❌ Your patch check has failed because the patch coverage (66.31%) is below the target coverage (75.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
Files with missing lines Coverage Δ
...de/fraunhofer/aisec/cpg/graph/ExpressionBuilder.kt 86.94% <ø> (-0.05%) ⬇️
...kotlin/de/fraunhofer/aisec/cpg/graph/Extensions.kt 60.86% <100.00%> (-0.07%) ⬇️
...kotlin/de/fraunhofer/aisec/cpg/graph/Interfaces.kt 55.00% <ø> (ø)
.../main/kotlin/de/fraunhofer/aisec/cpg/graph/Name.kt 88.67% <100.00%> (+2.40%) ⬆️
...otlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt 79.50% <100.00%> (+1.05%) ⬆️
...otlin/de/fraunhofer/aisec/cpg/graph/OverlayNode.kt 85.71% <100.00%> (+10.71%) ⬆️
...nhofer/aisec/cpg/graph/declarations/Declaration.kt 92.30% <100.00%> (+1.00%) ⬆️
...isec/cpg/graph/declarations/DeclarationSequence.kt 100.00% <ø> (ø)
...aunhofer/aisec/cpg/graph/declarations/Extension.kt 76.92% <ø> (ø)
...raunhofer/aisec/cpg/graph/declarations/Function.kt 71.13% <100.00%> (ø)
... and 41 more

... and 3 files with indirect coverage changes

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@KuechA KuechA marked this pull request as ready for review June 15, 2026 12:18
@KuechA KuechA added the publish-to-github-packages If added to a PR, builds from it will be published as a GitHub package label Jun 26, 2026

@oxisto oxisto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So it's good that it seems to lower memory pressure, I suspect it's mainly about the edge collections. Unfortunately they now went from barely manageable code to completely unmanageable code :(

@Relationship(value = "INVOKES", direction = Relationship.Direction.INCOMING)
val calledByEdges: Invokes<Function> =
Invokes<Function>(this, Call::invokeEdges, outgoing = false)
Invokes<Function>(this, mirroredCollection = { (it as Call).invokeEdges }, outgoing = false)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this seems very ... hacky :D can we improve the function/constructor interface somehow to make this more readable? the old style was very readable in contrast.

import de.fraunhofer.aisec.cpg.persistence.Relationship
import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation

interface HasLocals {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

needs kdoc

(if (parent != null) parent.toString() + delimiter else "") + localName
private var qualifiedFullNameCache: String? = null

private fun fullName(): String {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why is this a function now instead of a property? that changes things on many places in the code unnecessary and might even impact serialization.

Can't you just use val fullName { get() { lazy { .... } } which basically does what you want.


// For most references, code and name are the same token. If their textual value matches,
// reuse the name string instance to avoid duplicate string objects.
if (this is Reference) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't the code already set at this stage? so effectible you are adding more memory pressure here until the GC decides to clean up the original code reference string. I am not sure if this is actually of any benefit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

publish-to-github-packages If added to a PR, builds from it will be published as a GitHub package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants