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

Reduce memory allocations #452

Merged

Conversation

lahma
Copy link
Collaborator

@lahma lahma commented Dec 22, 2017

This time around again trying to reduce memory allocations to give virtual machine some breathing room. Most of the changes should have positive changes all around.

  • remove LINQ from hot paths
  • use List where possible to get rid of memory allocations when using foreach
  • cache empty completions

Next I'm going to tackle generally ObjectInstance and it's memory usage, trying to optimize MruPropertyCache2 etc.

UncacheableExpressionsBenchmark

Before (dev branch)

Method N Mean Error StdDev Gen 0 Gen 1 Allocated
Benchmark 500 1.094 s 0.0049 s 0.0071 s 243554.1667 15075.0000 997.15 MB

After (this pull request)

Method N Mean Error StdDev Gen 0 Gen 1 Allocated
Benchmark 500 1.057 s 0.0070 s 0.0105 s 204179.1667 50595.8333 905.73 MB

ArrayStressBenchmark

Before

Method N Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Jint 20 2.656 s 0.1310 s 0.0074 s 244000.0000 20250.0000 10000.0000 1.04 GB

After

Method N Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Jint 20 2.588 s 3.788 s 0.2140 s 217750.0000 21000.0000 10250.0000 956.95 MB

Jint/Engine.cs Outdated
public void DeclarationBindingInstantiation(DeclarationBindingType declarationBindingType, IEnumerable<FunctionDeclaration> functionDeclarations, IEnumerable<VariableDeclaration> variableDeclarations, FunctionInstance functionInstance, JsValue[] arguments)
public void DeclarationBindingInstantiation(
DeclarationBindingType declarationBindingType,
IList<FunctionDeclaration> functionDeclarations,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

IList gives us indexing but not allocation free foreacher, so using indexing

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason to not use List<T> here?

Copy link
Contributor

Choose a reason for hiding this comment

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

In particular, I'm thinking about bound check elimintations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The problem here is (like other places too) that we are dealing with public API. Changing to concrete implementations might not be the prettiest thing, even though best performing. I think @sebastienros can be the judge of this.

Jint/Engine.cs Outdated
var varAlreadyDeclared = env.HasBinding(dn);
if (!varAlreadyDeclared)
var variableDeclaration = variableDeclarations[i];
var declarations = (List<VariableDeclarator>) variableDeclaration.Declarations;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is a repeating pattern, we know Esprima and that it produces List, we can cast to it can get non-virtual dispatch + allocation free foreach

Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth just changing it there, no? That would give also skip the type checks here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have a pending pull request sebastienros/esprima-dotnet#13 that optimizes things, but does not change the API. Same thing here about setting the public API to concrete implementations. I guess streaming API like IEnumerable will not be supported in the near future and everything is materialized as is.

Forced cast is pretty much safe though as unit tests cover well all these and upgrading to different kind of Esprima would show up.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've created separate pull request to change Ast to have concerete types: sebastienros/esprima-dotnet#14

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Concrete type PR went in, but requires NuGet release to be used here.

Copy link
Owner

Choose a reason for hiding this comment

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

Pushed on Nuget, should appear soon.

@lahma lahma changed the title #451 reduce memory allocations Reduce memory allocations Dec 22, 2017
@lahma
Copy link
Collaborator Author

lahma commented Dec 25, 2017

I've upgraded to latest Esprima and cleaned the casts, removed Linq from DefaultTypeConverter too. I unfortunately missed the HoistingScope members but they have an API cleanup PR pending that fixes them too.

Can we merge at this point?

@lahma lahma force-pushed the perf/remove-linq-from-hot-paths branch 3 times, most recently from f719d32 to 9da94db Compare January 2, 2018 19:00
@lahma lahma force-pushed the perf/remove-linq-from-hot-paths branch from 9da94db to a247d12 Compare January 2, 2018 19:36
@sebastienros sebastienros merged commit 6164795 into sebastienros:dev Jan 2, 2018
@lahma lahma deleted the perf/remove-linq-from-hot-paths branch January 3, 2018 05:43
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.

None yet

3 participants