blob: 03db4da07d892464f82c2ec9c1d9a36785f9fe47 [file] [log] [blame]
/*
* 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.sysml.hops;
import java.util.ArrayList;
import org.apache.sysml.lops.FunctionCallCP;
import org.apache.sysml.lops.Lop;
import org.apache.sysml.lops.LopsException;
import org.apache.sysml.lops.LopProperties.ExecType;
import org.apache.sysml.parser.Expression.DataType;
import org.apache.sysml.parser.Expression.ValueType;
import org.apache.sysml.runtime.controlprogram.Program;
import org.apache.sysml.runtime.controlprogram.parfor.opt.CostEstimatorHops;
/**
* This FunctionOp represents the call to a DML-bodied or external function.
*
* Note: Currently, we support expressions in function arguments but no function calls
* in expressions.
*/
public class FunctionOp extends Hop
{
public static String OPSTRING = "extfunct";
public enum FunctionType{
DML,
EXTERNAL_MEM,
EXTERNAL_FILE,
MULTIRETURN_BUILTIN,
UNKNOWN
}
private FunctionType _type = null;
private String _fnamespace = null;
private String _fname = null;
private String[] _outputs = null;
private ArrayList<Hop> _outputHops = null;
private FunctionOp() {
//default constructor for clone
}
public FunctionOp(FunctionType type, String fnamespace, String fname, ArrayList<Hop> finputs, String[] outputs, ArrayList<Hop> outputHops) {
this(type, fnamespace, fname, finputs, outputs);
_outputHops = outputHops;
}
public FunctionOp(FunctionType type, String fnamespace, String fname, ArrayList<Hop> finputs, String[] outputs)
{
super(fnamespace + Program.KEY_DELIM + fname, DataType.UNKNOWN, ValueType.UNKNOWN );
_type = type;
_fnamespace = fnamespace;
_fname = fname;
_outputs = outputs;
for( Hop in : finputs )
{
getInput().add(in);
in.getParent().add(this);
}
}
public String getFunctionNamespace()
{
return _fnamespace;
}
public String getFunctionName()
{
return _fname;
}
public void setFunctionName( String fname )
{
_fname = fname;
}
public ArrayList<Hop> getOutputs() {
return _outputHops;
}
public String[] getOutputVariableNames()
{
return _outputs;
}
public FunctionType getFunctionType()
{
return _type;
}
@Override
public boolean allowsAllExecTypes() {
return false;
}
@Override
public void computeMemEstimate( MemoTable memo )
{
//overwrites default hops behavior
if( _type == FunctionType.DML )
_memEstimate = 1; //minimal mem estimate
else if( _type == FunctionType.EXTERNAL_MEM )
_memEstimate = 2* getInputSize(); //in/out
else if( _type == FunctionType.EXTERNAL_FILE || _type == FunctionType.UNKNOWN )
_memEstimate = CostEstimatorHops.DEFAULT_MEM_MR;
else if ( _type == FunctionType.MULTIRETURN_BUILTIN ) {
boolean outputDimsKnown = true;
for(Hop out : getOutputs()){
outputDimsKnown &= out.dimsKnown();
}
if( outputDimsKnown ) {
long lnnz = ((_nnz>=0)?_nnz:_dim1*_dim2);
_outputMemEstimate = computeOutputMemEstimate( _dim1, _dim2, lnnz );
_processingMemEstimate = computeIntermediateMemEstimate(_dim1, _dim2, lnnz);
}
_memEstimate = getInputOutputSize();
}
}
@Override
protected double computeOutputMemEstimate( long dim1, long dim2, long nnz )
{
if ( getFunctionType() != FunctionType.MULTIRETURN_BUILTIN )
throw new RuntimeException("Invalid call of computeOutputMemEstimate in FunctionOp.");
else {
if ( getFunctionName().equalsIgnoreCase("qr") ) {
// upper-triangular and lower-triangular matrices
long outputH = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(0).getDim1(), getOutputs().get(0).getDim2(), 0.5);
long outputR = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(1).getDim1(), getOutputs().get(1).getDim2(), 0.5);
return outputH+outputR;
}
else if ( getFunctionName().equalsIgnoreCase("lu") ) {
// upper-triangular and lower-triangular matrices
long outputP = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(1).getDim1(), getOutputs().get(1).getDim2(), 1.0/getOutputs().get(1).getDim2());
long outputL = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(0).getDim1(), getOutputs().get(0).getDim2(), 0.5);
long outputU = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(1).getDim1(), getOutputs().get(1).getDim2(), 0.5);
return outputL+outputU+outputP;
}
else if ( getFunctionName().equalsIgnoreCase("eigen") ) {
long outputVectors = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(0).getDim1(), getOutputs().get(0).getDim2(), 1.0);
long outputValues = OptimizerUtils.estimateSizeExactSparsity(getOutputs().get(1).getDim1(), 1, 1.0);
return outputVectors+outputValues;
}
else
throw new RuntimeException("Invalid call of computeOutputMemEstimate in FunctionOp.");
}
}
@Override
protected double computeIntermediateMemEstimate( long dim1, long dim2, long nnz )
{
if ( getFunctionType() != FunctionType.MULTIRETURN_BUILTIN )
throw new RuntimeException("Invalid call of computeIntermediateMemEstimate in FunctionOp.");
else {
if ( getFunctionName().equalsIgnoreCase("qr") ) {
// matrix of size same as the input
double interOutput = OptimizerUtils.estimateSizeExactSparsity(getInput().get(0).getDim1(), getInput().get(0).getDim2(), 1.0);
//System.out.println("QRInter " + interOutput/1024/1024);
return interOutput;
}
else if ( getFunctionName().equalsIgnoreCase("lu")) {
// 1D vector
double interOutput = OptimizerUtils.estimateSizeExactSparsity(getInput().get(0).getDim1(), 1, 1.0);
//System.out.println("LUInter " + interOutput/1024/1024);
return interOutput;
}
else if ( getFunctionName().equalsIgnoreCase("eigen")) {
// One matrix of size original input and three 1D vectors (used to represent tridiagonal matrix)
double interOutput = OptimizerUtils.estimateSizeExactSparsity(getInput().get(0).getDim1(), getInput().get(0).getDim2(), 1.0)
+ 3*OptimizerUtils.estimateSizeExactSparsity(getInput().get(0).getDim1(), 1, 1.0);
//System.out.println("EigenInter " + interOutput/1024/1024);
return interOutput;
}
else
throw new RuntimeException("Invalid call of computeIntermediateMemEstimate in FunctionOp.");
}
}
@Override
protected long[] inferOutputCharacteristics( MemoTable memo )
{
throw new RuntimeException("Invalid call of inferOutputCharacteristics in FunctionOp.");
}
@Override
public Lop constructLops()
throws HopsException, LopsException
{
//return already created lops
if( getLops() != null )
return getLops();
ExecType et = optFindExecType();
//construct input lops (recursive)
ArrayList<Lop> tmp = new ArrayList<Lop>();
for( Hop in : getInput() )
tmp.add( in.constructLops() );
//construct function call
FunctionCallCP fcall = new FunctionCallCP( tmp, _fnamespace, _fname, _outputs, _outputHops, et );
setLineNumbers( fcall );
setLops( fcall );
//note: no reblock lop because outputs directly bound
return getLops();
}
@Override
public String getOpString()
{
return OPSTRING;
}
@Override
protected ExecType optFindExecType()
throws HopsException
{
checkAndSetForcedPlatform();
if ( getFunctionType() == FunctionType.MULTIRETURN_BUILTIN ) {
// check if there is sufficient memory to execute this function
if( getFunctionName().equalsIgnoreCase("transformencode") ) {
_etype = ((_etypeForced==ExecType.SPARK
|| (getMemEstimate() >= OptimizerUtils.getLocalMemBudget()
&& OptimizerUtils.isSparkExecutionMode())) ? ExecType.SPARK : ExecType.CP);
}
else {
// Since the memory estimate is only conservative, do not throw
// exception if the estimated memory is larger than the budget
// Nevertheless, memory estimates these functions are useful for
// other purposes, such as compiling parfor
_etype = ExecType.CP;
}
}
else {
// the actual function call is always CP
_etype = ExecType.CP;
}
return _etype;
}
@Override
public void refreshSizeInformation()
{
//do nothing
}
@Override
@SuppressWarnings("unchecked")
public Object clone() throws CloneNotSupportedException
{
FunctionOp ret = new FunctionOp();
//copy generic attributes
ret.clone(this, false);
//copy specific attributes
ret._type = _type;
ret._fnamespace = _fnamespace;
ret._fname = _fname;
ret._outputs = _outputs.clone();
if( _outputHops != null )
ret._outputHops = (ArrayList<Hop>) _outputHops.clone();
return ret;
}
@Override
public boolean compare( Hop that )
{
return false;
}
}