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

[GR-43361] [GR-50205] Whole-Program Sparse Conditional Constant Propagation #9821

Merged
merged 1 commit into from
Oct 5, 2024

Conversation

graalvmbot
Copy link
Collaborator

This PR implements Whole-Program Sparse Conditional Constant Propagation (WP-SCCP) as an extensions of the points-to analysis in Native Image.

In a short summary, this PR adds predicate edges to the typeflow graph and introduces new flows for representing simple operations on primitive values, e.g. PrimitiveFilterTypeFlow. For scalability, primitives are modelled by a very simple lattice with Empty, Constant values and Any, see PrimitiveTypeState for details. No sets or intervals yet.

WP SCCP is hidden behind flags -H:+TrackPrimitiveValues and -H:+UsePredicates, which will be disabled by default, but we plan to enable them in near future.

Most Notable Changes

  • The infrastructure forPointstoOptions.TrackPrimitiveValues is extended with new types of flows.
  • PointstoOptions.UsePredicates is introduced, but disabled by default (depends on TrackPrimitiveValues).
    • To try WP SCCP, it is enough to use -H:+TrackPrimitiveValues and -H:+UsePredicates. The rest of the description applies only when you enable these two flags, otherwise there should be no observable differences in terms of how the analysis behaves.
  • TypeFlow nodes are now separated into two categories: local and global. Local is the default, and global ones, e.g. AllInstantiatedTypeFlow, implement a marker GlobalFlow interface.
  • All local TypeFlow nodes are disabled by default, i.e. they can receive updates from their dependencies, but they do not propagate anything further until they are enabled.
  • A third kind of edge called predicate edge is introduced into the typeflow graph.
  • Once a flow is enabled and has a non-empty typestate, it enables all the flows to which it is connected via a predicate edge.
  • New flows are introduced to represent more Graal IR nodes mainly for handling primitive operations, e.g. ConditionalFlow for a ConditionalNode.
    • Arithmetic operations are intentionally not handled. Unsuported nodes get represented by AnyPrimitiveSourceTypeFlow, which, once enabled, cause immediate saturation of all their enabled usages.

Evaluation

When benchmarking the enterprise non-pgo configuration, we have observed a reduction in binary size across all our benchmarks without impacting the build time. The same should apply for the other configurations.

Potential Risks

I divide the risks into internal and external from the point of view of the analysis.

Internal

The biggest internal risk are concurrency issues, which could result in non-deterministic builds and transient gate failures. The analysis is massively parallel and it is quite easy to introduce a data race or an atomicity violation resulting in a missed update. To mitigate this risk, I've run the whole gate infrastructure multiple times (apologies to the CI team), went through all the key methods manually and currently I am experimenting with noise insertion, but that of course does not fully prove an absence of these bugs, since they can manifest rarely.

Other risks are potential increase in analysis time and/or memory consumption, which is answered in the evaluation.

External

Missing Information

The biggest external risk is missing information about fields or methods that behave in a way the analysis cannot understand without explicit configuration. Missing UnknownPrimitiveField and UnknownObjectField annotations or forgetting to mark a method as opaqueReturn fall into this category.

However, another dependency can be seen for example in the TruffleFeature.beforeAnalysis which marks a set of methods as root and assume that the rest of Truffle will be always reachable (so in a way depends on an imprecision of the analysis) or TruffleBaseFeature.registerUnsafeAccess which does an optimization that is aguably not completely correct, but the issue cannot manifest in anything except from artificial little Truffle images that end up not running any Truffle language.

Overall, the SVM code has to be analysis-aware and always provide correct information about all 'opaque' usages and ideally also verify that the analysis results make sense (e.g. TruffleFeature could perform some check ensuring all the classes are truly reachable, turn the implicit assumption into an explicit one). I'd like to note that this statement was true before the changes in the PR, but the increased precision and the propagation of primitive values make it even more important.

Compiler Optimizations

Another external risk is the impact of this PR on compiler optimizations. Applying the results of the analysis reduces the amount of reachable methods and has an impact on the structure and size of the ones that remain reachable (more constant folding and pruning of unreachable branches). These changes can results e.g. in different inlining decisions.

Review

For the review, it is probably best to go as follows:

  1. Start from the TypeFlow class and see how it is changed.
  2. Inspect the newly created flows and updates that were done to the existing ones.
  3. Look at the MethodTypeFlowBuilder to see how are the new flows created and how we establish predicate edges between them.
  4. Look at the changes in StrengthenGraphs to see how the results are applied.
  5. Look at the rest of the PR.

Extensions

Some ideas that can and possibly will be done in a follow up:

  • Enable WP SCCP by default.
  • Try to reduce the amount of extra state this PR adds to the TypeFlow class.
  • Delay the other registrations from MethodTypeFlowBuilder.registerUsedElements. For example fields load and stores should be quite straightforward. Constants might be a bit harder, but I have an approach for them as well.
  • Support more Graal IR nodes (see comments on the PR directly).
  • Make predicates compatible with context sensitivity. More work there is necessary.
  • Use Graal IR stamps or other more complex representation for primitive values instead of the simple lattice (ongoing research).

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Oct 5, 2024
@graalvmbot graalvmbot closed this Oct 5, 2024
@graalvmbot graalvmbot deleted the d-kozak/GR-43361/wp-sccp-2-predicates-clean branch October 5, 2024 14:33
@graalvmbot graalvmbot merged commit c9658c9 into master Oct 5, 2024
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCA Verified All contributors have signed the Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants