[K/N][optmz] Better escape analysis divergence handling

This commit is contained in:
Igor Chevdar
2022-10-31 09:02:08 +02:00
committed by Space Team
parent 8ed6c1a06c
commit 4fd64fad2f
@@ -558,7 +558,6 @@ internal object EscapeAnalysis {
} }
} }
val nonTrivialComponent = nodes.size > 1
val pointsToGraphs = mutableMapOf<DataFlowIR.FunctionSymbol.Declared, PointsToGraph>() val pointsToGraphs = mutableMapOf<DataFlowIR.FunctionSymbol.Declared, PointsToGraph>()
val toAnalyze = mutableSetOf<DataFlowIR.FunctionSymbol.Declared>() val toAnalyze = mutableSetOf<DataFlowIR.FunctionSymbol.Declared>()
toAnalyze.addAll(nodes) toAnalyze.addAll(nodes)
@@ -574,33 +573,40 @@ internal object EscapeAnalysis {
val pointsToGraph = PointsToGraph(function) val pointsToGraph = PointsToGraph(function)
pointsToGraphs[function] = pointsToGraph pointsToGraphs[function] = pointsToGraph
analyze(callGraph, pointsToGraph, function)
val endResult = escapeAnalysisResults[function]!!
if (startResult == endResult) { val maxAllowedGraphSize = with(DivergenceResolutionParams) {
context.log { "Escape analysis is not changed" } // A heuristic: the majority of functions have their points-to graph size linear in number of IR (or DFG) nodes,
} else { // there are exceptions but it's a trade-off we have to make.
context.log { "Escape analysis was refined:\n$endResult" } // The trick with [NegligibleSize] handles functions that basically delegate their work to other functions.
if (with(DivergenceResolutionParams) { val numberOfNodes = intraproceduralAnalysisResults[function]!!.function.body.allScopes.sumOf { it.nodes.size }
// A heuristic: the majority of functions have their points-to graph size linear in number of IR (or DFG) nodes, NegligibleSize + numberOfNodes * SwellingFactor
// there are exceptions but it's a trade-off we have to make. }
// The trick with [NegligibleSize] handles functions that basically delegate their work to other functions.
val numberOfNodes = intraproceduralAnalysisResults[function]!!.function.body.allScopes.sumOf { it.nodes.size }
val maxAllowedGraphSize = NegligibleSize + numberOfNodes * SwellingFactor
numberOfRuns[function]!! > MaxAttempts var analyzedSuccessfully = analyze(callGraph, pointsToGraph, function, maxAllowedGraphSize)
|| (nonTrivialComponent && pointsToGraph.allNodes.size > maxAllowedGraphSize) var processCallers = true
} if (analyzedSuccessfully) {
) { val endResult = escapeAnalysisResults[function]!!
// TODO: suboptimal. May be it is possible somehow handle the entire component at once? if (startResult == endResult) {
context.log { context.log { "Escape analysis is not changed" }
"WARNING: Escape analysis for $function seems not to be converging." + processCallers = false
" Assuming conservative results." } else {
} context.log { "Escape analysis was refined:\n$endResult" }
escapeAnalysisResults[function] = FunctionEscapeAnalysisResult.pessimistic(function.parameters.size) if (numberOfRuns[function]!! > DivergenceResolutionParams.MaxAttempts)
nodes.remove(function) analyzedSuccessfully = false
} }
}
if (!analyzedSuccessfully) {
// TODO: suboptimal. May be it is possible somehow handle the entire component at once?
context.log {
"WARNING: Escape analysis for $function seems not to be converging." +
" Assuming conservative results."
}
escapeAnalysisResults[function] = FunctionEscapeAnalysisResult.pessimistic(function.parameters.size)
nodes.remove(function)
}
if (processCallers) {
callGraph.reversedEdges[function]?.forEach { callGraph.reversedEdges[function]?.forEach {
if (nodes.contains(it)) if (nodes.contains(it))
toAnalyze.add(it) toAnalyze.add(it)
@@ -659,19 +665,27 @@ internal object EscapeAnalysis {
private fun arraySize(itemSize: Int, length: Int): Long = private fun arraySize(itemSize: Int, length: Int): Long =
pointerSize /* typeinfo */ + 4 /* size */ + itemSize * length.toLong() pointerSize /* typeinfo */ + 4 /* size */ + itemSize * length.toLong()
private fun analyze(callGraph: CallGraph, pointsToGraph: PointsToGraph, function: DataFlowIR.FunctionSymbol.Declared) { private fun analyze(
context.log {"Before calls analysis" } callGraph: CallGraph,
pointsToGraph: PointsToGraph,
function: DataFlowIR.FunctionSymbol.Declared,
maxAllowedGraphSize: Int
): Boolean {
context.log { "Before calls analysis" }
pointsToGraph.log() pointsToGraph.log()
pointsToGraph.logDigraph(false) pointsToGraph.logDigraph(false)
callGraph.directEdges[function]!!.callSites.forEach { callGraph.directEdges[function]!!.callSites.forEach {
val callee = it.actualCallee val callee = it.actualCallee
val calleeEAResult = if (it.isVirtual) val calleeEAResult = if (it.isVirtual)
getExternalFunctionEAResult(it) getExternalFunctionEAResult(it)
else else
callGraph.directEdges[callee]?.let { escapeAnalysisResults[it.symbol]!! } callGraph.directEdges[callee]?.let { escapeAnalysisResults[it.symbol]!! }
?: getExternalFunctionEAResult(it) ?: getExternalFunctionEAResult(it)
pointsToGraph.processCall(it, calleeEAResult) pointsToGraph.processCall(it, calleeEAResult)
if (pointsToGraph.allNodes.size > maxAllowedGraphSize)
return false
} }
context.log { "After calls analysis" } context.log { "After calls analysis" }
@@ -686,6 +700,8 @@ internal object EscapeAnalysis {
pointsToGraph.logDigraph(true) pointsToGraph.logDigraph(true)
escapeAnalysisResults[function] = eaResult escapeAnalysisResults[function] = eaResult
return true
} }
private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol { private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol {