Repository: systemml Updated Branches: refs/heads/master d0ef4263e -> e368de8d4 (forced update)
[SYSTEMML-2021] Fix robustness codegen optimizer (opening heuristic) This patch fixes the robustness of the codegen plan enumeration, which got stuck for the perftest stratstats due to a large fusion partition with 38 interesting points and very specific cost characteristics that rendered the open heuristic fuse-all ineffective. We now run both heuristics (fused-all and fuse-no-redundancy) as a consolidated opening heuristics to quickly obtain a good lower bound. Furthermore, we also avoid enumerating large partitions (w/ >20 interesting points) if the opening heuristic already achieved costs that are in an epsilon environment (1%) of the minimal static costs of this partition. Together, these modifications greatly improve the robustness of the codegen optimizer without missing any meaningful plans. Project: http://git-wip-us.apache.org/repos/asf/systemml/repo Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/e368de8d Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/e368de8d Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/e368de8d Branch: refs/heads/master Commit: e368de8d4bd0df4c44ce62cf2bff6b4595719893 Parents: db3d54c Author: Matthias Boehm <mboe...@gmail.com> Authored: Fri Nov 17 21:32:25 2017 -0800 Committer: Matthias Boehm <mboe...@gmail.com> Committed: Fri Nov 17 22:20:16 2017 -0800 ---------------------------------------------------------------------- .../opt/PlanSelectionFuseCostBasedV2.java | 38 +++++++++++++++----- 1 file changed, 30 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/systemml/blob/e368de8d/src/main/java/org/apache/sysml/hops/codegen/opt/PlanSelectionFuseCostBasedV2.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/hops/codegen/opt/PlanSelectionFuseCostBasedV2.java b/src/main/java/org/apache/sysml/hops/codegen/opt/PlanSelectionFuseCostBasedV2.java index 80013c5..08d5e44 100644 --- a/src/main/java/org/apache/sysml/hops/codegen/opt/PlanSelectionFuseCostBasedV2.java +++ b/src/main/java/org/apache/sysml/hops/codegen/opt/PlanSelectionFuseCostBasedV2.java @@ -96,6 +96,12 @@ public class PlanSelectionFuseCostBasedV2 extends PlanSelection //sparsity estimate for unknown sparsity to prefer sparse-safe fusion plans private static final double SPARSE_SAFE_SPARSITY_EST = 0.1; + //after evaluating the costs of the opening heuristics fuse-all and fuse-no-redundancy, + //remaining candidate plans of large partitions (w/ >= COST_MIN_EPS_NUM_POINTS) are + //only evaluated if the current costs are > (1+COST_MIN_EPS) * static (i.e., minimal) costs. + public static final double COST_MIN_EPS = 0.01; //1% + public static final double COST_MIN_EPS_NUM_POINTS = 20; //2^20 = 1M plans + //optimizer configuration public static boolean COST_PRUNING = true; public static boolean STRUCTURAL_PRUNING = true; @@ -161,7 +167,7 @@ public class PlanSelectionFuseCostBasedV2 extends PlanSelection for( Long hopID : part.getPartition() ) memo.pruneRedundant(hopID, true, part.getMatPointsExt()); } - + //enumerate and cost plans, returns optional plan boolean[] bestPlan = enumPlans(memo, part, costs, rgraph, part.getMatPointsExt(), 0); @@ -205,14 +211,28 @@ public class PlanSelectionFuseCostBasedV2 extends PlanSelection //scan linearized search space, w/ skips for branch and bound pruning //and structural pruning (where we solve conditionally independent problems) //bestC is monotonically non-increasing and serves as the upper bound - final long len = UtilFunctions.pow(2, matPoints.length-off); - boolean[] bestPlan = null; - double bestC = Double.MAX_VALUE; + final int Mlen = matPoints.length-off; + final long len = UtilFunctions.pow(2, Mlen); long numEvalPlans = 0, numEvalPartPlans = 0; - for( long i=0; i<len; i++ ) { + //evaluate heuristics fuse-all and fuse-no-redundancy to quickly obtain a good lower bound + final boolean[] plan0 = createAssignment(Mlen, off, 0); // fuse-all + final boolean[] planN = createAssignment(Mlen, off, len-1); //fuse-no-redundancy + final double C0 = getPlanCost(memo, part, matPoints, plan0, costs._computeCosts, Double.MAX_VALUE); + final double CN = getPlanCost(memo, part, matPoints, planN, costs._computeCosts, Double.MAX_VALUE); + boolean[] bestPlan = (C0 <= CN) ? plan0 : planN; + double bestC = Math.min(C0, CN); + final boolean evalRemain = (Mlen < COST_MIN_EPS_NUM_POINTS + || !COST_PRUNING || bestC > (1+COST_MIN_EPS) * costs.getMinCosts()); + if( LOG.isTraceEnabled() ) + LOG.trace("Enum opening: " + Arrays.toString(bestPlan) + " -> " + bestC); + if( !evalRemain ) + LOG.warn("Skip enum for |M|="+Mlen+", C="+bestC+", Cmin="+costs.getMinCosts()); + + //evaluate remaining plans, except already evaluated heuristics + for( long i=1; i<len-1 & evalRemain; i++ ) { //construct assignment - boolean[] plan = createAssignment(matPoints.length-off, off, i); + boolean[] plan = createAssignment(Mlen, off, i); long pskip = 0; //skip after costing //skip plans with structural pruning @@ -281,7 +301,7 @@ public class PlanSelectionFuseCostBasedV2 extends PlanSelection LOG.trace("Enum: Optimal plan: "+Arrays.toString(bestPlan)); //copy best plan w/o fixed offset plan - return (bestPlan==null) ? new boolean[matPoints.length-off] : + return (bestPlan==null) ? new boolean[Mlen] : Arrays.copyOfRange(bestPlan, off, bestPlan.length); } @@ -1100,13 +1120,15 @@ public class PlanSelectionFuseCostBasedV2 extends PlanSelection public final double _compute; public final double _read; public final double _write; - public StaticCosts(HashMap<Long,Double> allComputeCosts, double computeCost, double readCost, double writeCost) { _computeCosts = allComputeCosts; _compute = computeCost; _read = readCost; _write = writeCost; } + public double getMinCosts() { + return Math.max(_read, _compute) + _write; + } } private static class AggregateInfo {