blob: 4bf2e5606a9c768cc0cfc8d8bfcb89457bd14c2a [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.hops.fedplanner;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.sysds.common.Types.ExecType;
import org.apache.sysds.common.Types.OpOpData;
import org.apache.sysds.hops.DataOp;
import org.apache.sysds.hops.Hop;
import org.apache.sysds.hops.fedplanner.FTypes.FType;
import org.apache.sysds.hops.ipa.FunctionCallGraph;
import org.apache.sysds.hops.ipa.FunctionCallSizeInfo;
import org.apache.sysds.hops.rewrite.HopRewriteUtils;
import org.apache.sysds.parser.DMLProgram;
import org.apache.sysds.parser.ForStatement;
import org.apache.sysds.parser.ForStatementBlock;
import org.apache.sysds.parser.FunctionStatement;
import org.apache.sysds.parser.FunctionStatementBlock;
import org.apache.sysds.parser.IfStatement;
import org.apache.sysds.parser.IfStatementBlock;
import org.apache.sysds.parser.StatementBlock;
import org.apache.sysds.parser.WhileStatement;
import org.apache.sysds.parser.WhileStatementBlock;
import org.apache.sysds.runtime.controlprogram.LocalVariableMap;
import org.apache.sysds.runtime.controlprogram.caching.CacheableData;
import org.apache.sysds.runtime.instructions.cp.Data;
import org.apache.sysds.runtime.instructions.fed.FEDInstruction.FederatedOutput;
/**
* Baseline federated planner that compiles all hops
* that support federated execution on federated inputs to
* forced federated operations.
*/
public class FederatedPlannerFedAll extends AFederatedPlanner {
@Override
public void rewriteProgram( DMLProgram prog,
FunctionCallGraph fgraph, FunctionCallSizeInfo fcallSizes )
{
// handle main program
Map<String, FType> fedVars = new HashMap<>();
for(StatementBlock sb : prog.getStatementBlocks())
rRewriteStatementBlock(sb, fedVars);
}
@Override
public void rewriteFunctionDynamic(FunctionStatementBlock function, LocalVariableMap funcArgs) {
Map<String, FType> fedVars = new HashMap<>();
for(Map.Entry<String, Data> varName : funcArgs.entrySet()) {
Data data = varName.getValue();
FType fType = null;
if(data instanceof CacheableData<?> && ((CacheableData<?>) data).isFederated()) {
fType = ((CacheableData<?>) data).getFedMapping().getType();
}
fedVars.put(varName.getKey(), fType);
}
rRewriteStatementBlock(function, fedVars);
}
private void rRewriteStatementBlock(StatementBlock sb, Map<String, FType> fedVars) {
//TODO currently this rewrite assumes consistent decisions in conditional control flow
if (sb instanceof FunctionStatementBlock) {
FunctionStatementBlock fsb = (FunctionStatementBlock)sb;
FunctionStatement fstmt = (FunctionStatement)fsb.getStatement(0);
for (StatementBlock csb : fstmt.getBody())
rRewriteStatementBlock(csb, fedVars);
}
else if (sb instanceof WhileStatementBlock) {
WhileStatementBlock wsb = (WhileStatementBlock) sb;
WhileStatement wstmt = (WhileStatement)wsb.getStatement(0);
rRewriteHop(wsb.getPredicateHops(), new HashMap<>(), Collections.emptyMap());
for (StatementBlock csb : wstmt.getBody())
rRewriteStatementBlock(csb, fedVars);
}
else if (sb instanceof IfStatementBlock) {
IfStatementBlock isb = (IfStatementBlock) sb;
IfStatement istmt = (IfStatement)isb.getStatement(0);
rRewriteHop(isb.getPredicateHops(), new HashMap<>(), Collections.emptyMap());
for (StatementBlock csb : istmt.getIfBody())
rRewriteStatementBlock(csb, fedVars);
for (StatementBlock csb : istmt.getElseBody())
rRewriteStatementBlock(csb, fedVars);
}
else if (sb instanceof ForStatementBlock) { //incl parfor
ForStatementBlock fsb = (ForStatementBlock) sb;
ForStatement fstmt = (ForStatement)fsb.getStatement(0);
rRewriteHop(fsb.getFromHops(), new HashMap<>(), Collections.emptyMap());
rRewriteHop(fsb.getToHops(), new HashMap<>(), Collections.emptyMap());
rRewriteHop(fsb.getIncrementHops(), new HashMap<>(), Collections.emptyMap());
for (StatementBlock csb : fstmt.getBody())
rRewriteStatementBlock(csb, fedVars);
}
else //generic (last-level)
{
//process entire hop DAGs with memoization
Map<Long, FType> fedHops = new HashMap<>();
if( sb.getHops() != null )
for( Hop c : sb.getHops() )
rRewriteHop(c, fedHops, fedVars);
//TODO handle function calls
//propagate federated outputs across DAGs
if( sb.getHops() != null )
for( Hop c : sb.getHops() )
if( HopRewriteUtils.isData(c, OpOpData.TRANSIENTWRITE) )
fedVars.put(c.getName(), fedHops.get(c.getInput(0).getHopID()));
}
}
private void rRewriteHop(Hop hop, Map<Long, FType> memo, Map<String, FType> fedVars) {
if( memo.containsKey(hop.getHopID()) )
return; //already processed
//process children first
for( Hop c : hop.getInput() )
rRewriteHop(c, memo, fedVars);
//handle specific operators (except transient writes)
if( HopRewriteUtils.isData(hop, OpOpData.FEDERATED) )
memo.put(hop.getHopID(), deriveFType((DataOp)hop));
else if( HopRewriteUtils.isData(hop, OpOpData.TRANSIENTREAD) )
memo.put(hop.getHopID(), fedVars.get(hop.getName()));
else if( allowsFederated(hop, memo) ) {
hop.setForcedExecType(ExecType.FED);
memo.put(hop.getHopID(), getFederatedOut(hop, memo));
if( memo.get(hop.getHopID()) != null )
hop.setFederatedOutput(FederatedOutput.FOUT);
}
else // memoization as processed, but not federated
memo.put(hop.getHopID(), null);
}
}