/**
* (C) Copyright IBM Corp. 2010, 2015
*
* Licensed 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 com.ibm.bi.dml.runtime.controlprogram;
import java.util.ArrayList;
import java.util.HashMap;
import com.ibm.bi.dml.parser.DMLTranslator;
import com.ibm.bi.dml.parser.DataIdentifier;
import com.ibm.bi.dml.parser.ExternalFunctionStatement;
import com.ibm.bi.dml.parser.Expression.ValueType;
import com.ibm.bi.dml.runtime.DMLRuntimeException;
import com.ibm.bi.dml.runtime.controlprogram.caching.MatrixObject;
import com.ibm.bi.dml.runtime.controlprogram.context.ExecutionContext;
import com.ibm.bi.dml.runtime.controlprogram.parfor.util.IDSequence;
import com.ibm.bi.dml.runtime.instructions.Instruction;
import com.ibm.bi.dml.runtime.matrix.MatrixCharacteristics;
import com.ibm.bi.dml.runtime.matrix.MatrixFormatMetaData;
import com.ibm.bi.dml.runtime.matrix.data.InputInfo;
import com.ibm.bi.dml.runtime.matrix.data.OutputInfo;
import com.ibm.bi.dml.udf.ExternalFunctionInvocationInstruction;
import com.ibm.bi.dml.udf.Matrix;
import com.ibm.bi.dml.udf.PackageRuntimeException;
/**
* CP external function program block, that overcomes the need for
* BlockToCell and CellToBlock MR jobs by changing the contract for an external function.
* If execlocation="CP", the implementation of an external function must read and write
* matrices as InputInfo.BinaryBlockInputInfo and OutputInfo.BinaryBlockOutputInfo.
*
* Furthermore, it extends ExternalFunctionProgramBlock with a base directory in order
* to make it parallelizable, even in case of different JVMs. For this purpose every
* external function must implement a <SET_BASE_DIR> method.
*
*
*/
public class ExternalFunctionProgramBlockCP extends ExternalFunctionProgramBlock
{
public static String DEFAULT_FILENAME = "ext_funct";
private static IDSequence _defaultSeq = new IDSequence();
/**
* Constructor that also provides otherParams that are needed for external
* functions. Remaining parameters will just be passed to constructor for
* function program block.
*
* @param eFuncStat
* @throws DMLRuntimeException
*/
public ExternalFunctionProgramBlockCP(Program prog,
ArrayList<DataIdentifier> inputParams,
ArrayList<DataIdentifier> outputParams,
HashMap<String, String> otherParams,
String baseDir) throws DMLRuntimeException {
super(prog, inputParams, outputParams, baseDir); //w/o instruction generation
// copy other params
_otherParams = new HashMap<String, String>();
_otherParams.putAll(otherParams);
// generate instructions (overwritten)
createInstructions();
}
/**
* Method to be invoked to execute instructions for the external function
* invocation
* @throws DMLRuntimeException
*/
@Override
public void execute(ExecutionContext ec) throws DMLRuntimeException
{
_runID = _idSeq.getNextID();
ExternalFunctionInvocationInstruction inst = null;
// execute package function
for (int i=0; i < _inst.size(); i++)
{
try {
inst = (ExternalFunctionInvocationInstruction)_inst.get(i);
executeInstruction( ec, inst );
}
catch (Exception e){
throw new DMLRuntimeException(this.printBlockErrorLocation() + "Error evaluating instruction " + i + " in external function programBlock. inst: " + inst.toString(), e);
}
}
// check return values
checkOutputParameters(ec.getVariables());
}
/**
* Executes the external function instruction without the use of NIMBLE tasks.
*
* @param inst
* @throws DMLRuntimeException
* @throws NimbleCheckedRuntimeException
*/
@Override
public void executeInstruction(ExecutionContext ec, ExternalFunctionInvocationInstruction inst)
throws DMLRuntimeException
{
// After removal of nimble, we moved the code of ExternalFunctionProgramBlockCP to
// ExternalFunctionProgramBlock and hence hence both types of external functions can
// share the same code path here.
super.executeInstruction(ec, inst);
}
@Override
protected void createInstructions()
{
_inst = new ArrayList<Instruction>();
// assemble information provided through keyvalue pairs
String className = _otherParams.get(ExternalFunctionStatement.CLASS_NAME);
String configFile = _otherParams.get(ExternalFunctionStatement.CONFIG_FILE);
// class name cannot be null, however, configFile and execLocation can be null
if (className == null)
throw new PackageRuntimeException(this.printBlockErrorLocation() + ExternalFunctionStatement.CLASS_NAME + " not provided!");
// assemble input and output param strings
String inputParameterString = getParameterString(getInputParams());
String outputParameterString = getParameterString(getOutputParams());
// generate instruction
ExternalFunctionInvocationInstruction einst = new ExternalFunctionInvocationInstruction(
className, configFile, inputParameterString,
outputParameterString);
_inst.add(einst);
}
@Override
protected void modifyInputMatrix(Matrix m, MatrixObject mobj)
{
//pass in-memory object to external function
m.setMatrixObject( mobj );
}
@Override
protected MatrixObject createOutputMatrixObject(Matrix m)
{
MatrixObject ret = m.getMatrixObject();
if( ret == null ) //otherwise, pass in-memory matrix from extfunct back to invoking program
{
MatrixCharacteristics mc = new MatrixCharacteristics(m.getNumRows(),m.getNumCols(), DMLTranslator.DMLBlockSize, DMLTranslator.DMLBlockSize);
MatrixFormatMetaData mfmd = new MatrixFormatMetaData(mc, OutputInfo.BinaryBlockOutputInfo, InputInfo.BinaryBlockInputInfo);
ret = new MatrixObject(ValueType.DOUBLE, m.getFilePath(), mfmd);
}
//for allowing in-memory packagesupport matrices w/o filesnames
if( ret.getFileName().equals( DEFAULT_FILENAME ) )
{
ret.setFileName( createDefaultOutputFilePathAndName() );
}
return ret;
}
public String createDefaultOutputFilePathAndName( )
{
return _baseDir + DEFAULT_FILENAME + _defaultSeq.getNextID();
}
public String printBlockErrorLocation(){
return "ERROR: Runtime error in external function program block (for CP) generated from external function statement block between lines " + _beginLine + " and " + _endLine + " -- ";
}
}