Skip to content

Conversation

@saintentropy
Copy link
Contributor

Purpose

JIL Execution in the VM is responsible for a small but important subset of node execution. While most nodes today are executed via the FFI (Foreign Function Interpreter) mechanisms which invoke C# code, some basic utility methods especially in Math category are written in native design script. This type of function is handled by the JILFunctionEndPoint. While many of these enhancements are targeted at this execution path, they also yield net improvements to the general execution of all EndPoint types. This is especially true in the POP_Handler, DEP_Handler, SetupExecutive, and RestoreFromCall methods within the VM's Executive. For a specific test graph with a mixture of geometry and mathematical operations, these enhancements specifically improve JIL Execution by 75% (1.25s to .3s) but more importantly reduce overall UpdateGraph run time by 35% (17s to 13s). The net impact is also dramatically reduces memory allocation. For the case of this specific test graph the memory allocation associated with UpdateGraph went from 11.3gb to 3.6gb. In summary this PR optimizes the execution of functions handled via the JIL Endpoint but has a net improvement to all node types.

Specifically this PR does the following

  • Clean up dependency on CurrentStackFrame property of RuntimeMemory. This getter creates a new StackFrame object to reference a subset of items at a specific location in the VM's Stack. The CurentStackFrame property is utilized 99% of the time from the IsGlobalScope method. This issue is IsGlobalScope can be called tens of millions of times during a Graph Execution run which creates a new StackFrame object every time the CurrentStackFrame property is referenced. This optimization simply removes the need to allocate a temporary StackValue object when the data which is needed can be easily referenced directly from the Stack. This optimization represents the majority of the extra gigabytes of temporary allocation described above in the sample graph performance delta.

  • Refactor JILFunctionEndPoint to include an Init() function to allow caching of Interpreter. This mirrors a similar optimization that was applied to the FFIFunctionEndPoint (see this PR). The cached object can be reused via a ResetExecutive vs continuing to reallocate a new Interpreter object. This is applicable during replication.

  • Refactor RestoreFromCall to not allocate empty list until after the required check of runtimeCore.Options.RunMode == InterpreterMode.Expression. This allocation was done repeatedly when it the later Any() checks can be refactored to a null check.

  • Remove Linq implimentation from GetFirstDirtyGraphNodeFromPC. This method is also called often during GraphUpdate. This optimizations removes the linq implementation for a more memory and performance optimized implementation.

  • Fast path for GetGraphNodesAtScope when asking for a Invalid ClassIndex and ProcessIndex (ie -1). This is another function that can be called millions of times during a UpdateGraph run. Many calls that are routed through this function are looking for the same item in the graphNodeMap dictionary. This optimization creates a shortcut when the lookup is asking for the specific case of the invalid ClassIndex and ProcessIndex that avoids accessing the object from the dictionary. Note, in the case of this function, caching the previous lookup does not speed up the lookup as the method usage typically alternates between

  • Refactor UpdateGraph to not allocate a temporary list of GraphNodes.

[ ] Todo discuss single test failure

Declarations

Check these if you believe they are true

  • The codebase is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning and are documented in the API Changes document.
  • This PR modifies some build requirements and the readme is updated

Reviewers

TBD

FYIs

TBD

}

[Test]
[Category("Failure")]
Copy link
Contributor

Choose a reason for hiding this comment

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

??

return item;
}

return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

why is the for loop better than the Linq FirstOrDefault ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pinzart Not sure and may be an false postive from looking at the performance measurements. Regardless this ends up on the hot path so good to have a fast as possible.


return cachedNodes;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is trying to create and escape for the lookup the most common lookup if for the default kInvalidPC pair. Maybe a better way to do that or document that

@saintentropy
Copy link
Contributor Author

#12895 should replace this PR. It is now split into two

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants