blob: 35926961f2dd03e7f94e2bf4ffe9dd541a60cc16 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sysds.lops;
import org.apache.sysds.common.Types;
import org.apache.sysds.hops.AggBinaryOp;
import org.apache.sysds.parser.DMLProgram;
import org.apache.sysds.parser.StatementBlock;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class OperatorOrderingUtils
{
// Return a list representation of all the lops in a SB
public static ArrayList<Lop> getLopList(StatementBlock sb) {
ArrayList<Lop> lops = null;
if (sb.getLops() != null && !sb.getLops().isEmpty()) {
lops = new ArrayList<>();
for (Lop root : sb.getLops())
addToLopList(lops, root);
}
return lops;
}
// Determine if a lop is root of a DAG
public static boolean isLopRoot(Lop lop) {
if (lop.getOutputs().isEmpty())
return true;
//TODO: Handle internal builtins (e.g. eigen)
if (lop instanceof FunctionCallCP &&
((FunctionCallCP) lop).getFnamespace().equalsIgnoreCase(DMLProgram.INTERNAL_NAMESPACE)) {
return true;
}
return false;
}
// Gather the Spark operators which return intermediates to local (actions/single_block)
// In addition count the number of Spark OPs underneath every Operator
public static int collectSparkRoots(Lop root, Map<Long, Integer> sparkOpCount, List<Lop> sparkRoots) {
if (sparkOpCount.containsKey(root.getID())) //visited before
return sparkOpCount.get(root.getID());
// Aggregate #Spark operators in the child DAGs
int total = 0;
for (Lop input : root.getInputs())
total += collectSparkRoots(input, sparkOpCount, sparkRoots);
// Check if this node is Spark
total = root.isExecSpark() ? total + 1 : total;
sparkOpCount.put(root.getID(), total);
// Triggering point: Spark action/operator with all CP consumers
if (isSparkTriggeringOp(root)) {
sparkRoots.add(root);
root.setAsynchronous(true); //candidate for async. execution
}
return total;
}
// Dictionary of Spark operators which are expensive enough to be
// benefited from persisting if shared among jobs.
public static boolean isPersistableSparkOp(Lop lop) {
return lop.isExecSpark() && (lop instanceof MapMult
|| lop instanceof MMCJ || lop instanceof MMRJ
|| lop instanceof MMZip);
}
private static boolean isSparkTriggeringOp(Lop lop) {
boolean rightSpLop = lop.isExecSpark() && (lop.getAggType() == AggBinaryOp.SparkAggType.SINGLE_BLOCK
|| lop.getDataType() == Types.DataType.SCALAR || lop instanceof MapMultChain
|| lop instanceof PickByCount || lop instanceof MMZip || lop instanceof CentralMoment
|| lop instanceof CoVariance || lop instanceof MMTSJ || lop.isAllOutputsCP());
boolean isPrefetched = lop.getOutputs().size() == 1
&& lop.getOutputs().get(0) instanceof UnaryCP
&& ((UnaryCP) lop.getOutputs().get(0)).getOpCode().equalsIgnoreCase("prefetch");
boolean col2Bc = isCollectForBroadcast(lop);
boolean prefetch = (lop instanceof UnaryCP) &&
((UnaryCP) lop).getOpCode().equalsIgnoreCase("prefetch");
return (rightSpLop || col2Bc || prefetch) && !isPrefetched;
}
// Determine if the result of this operator is collected to
// broadcast for the next operator (e.g. mapmm --> map+)
public static boolean isCollectForBroadcast(Lop lop) {
boolean isSparkOp = lop.isExecSpark();
boolean isBc = lop.getOutputs().stream()
.allMatch(out -> (out.getBroadcastInput() == lop));
//TODO: Handle Lops with mixed Spark (broadcast) CP consumers
return isSparkOp && isBc && (lop.getDataType() == Types.DataType.MATRIX);
}
private static boolean addNode(ArrayList<Lop> lops, Lop node) {
if (lops.contains(node))
return false;
lops.add(node);
return true;
}
private static void addToLopList(ArrayList<Lop> lops, Lop lop) {
if (addNode(lops, lop))
for (Lop in : lop.getInputs())
addToLopList(lops, in);
}
}