blob: 3ac64b6018ef4e47deab4afdddb2b9b2951c5f19 [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.cost;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.sysds.common.Types;
import org.apache.sysds.hops.AggBinaryOp;
import org.apache.sysds.hops.AggUnaryOp;
import org.apache.sysds.hops.BinaryOp;
import org.apache.sysds.hops.DnnOp;
import org.apache.sysds.hops.Hop;
import org.apache.sysds.hops.IndexingOp;
import org.apache.sysds.hops.LiteralOp;
import org.apache.sysds.hops.NaryOp;
import org.apache.sysds.hops.ParameterizedBuiltinOp;
import org.apache.sysds.hops.ReorgOp;
import org.apache.sysds.hops.TernaryOp;
import org.apache.sysds.hops.UnaryOp;
import org.apache.sysds.hops.rewrite.HopRewriteUtils;
/**
* Class with methods estimating compute costs of operations.
*/
public class ComputeCost {
private static final Log LOG = LogFactory.getLog(ComputeCost.class.getName());
/**
* Get compute cost for given HOP based on the number of floating point operations per output cell
* and the total number of output cells.
* @param currentHop for which compute cost is returned
* @return compute cost of currentHop as number of floating point operations
*/
public static double getHOPComputeCost(Hop currentHop){
double costs = 1;
if( currentHop instanceof UnaryOp) {
switch( ((UnaryOp)currentHop).getOp() ) {
case ABS:
case ROUND:
case CEIL:
case FLOOR:
case SIGN: costs = 1; break;
case SPROP:
case SQRT: costs = 2; break;
case EXP: costs = 18; break;
case SIGMOID: costs = 21; break;
case LOG:
case LOG_NZ: costs = 32; break;
case NCOL:
case NROW:
case PRINT:
case ASSERT:
case CAST_AS_BOOLEAN:
case CAST_AS_DOUBLE:
case CAST_AS_INT:
case CAST_AS_MATRIX:
case CAST_AS_SCALAR: costs = 1; break;
case SIN: costs = 18; break;
case COS: costs = 22; break;
case TAN: costs = 42; break;
case ASIN: costs = 93; break;
case ACOS: costs = 103; break;
case ATAN: costs = 40; break;
case SINH: costs = 93; break; // TODO:
case COSH: costs = 103; break;
case TANH: costs = 40; break;
case CUMSUM:
case CUMMIN:
case CUMMAX:
case CUMPROD: costs = 1; break;
case CUMSUMPROD: costs = 2; break;
default:
LOG.warn("Cost model not "
+ "implemented yet for: "+((UnaryOp)currentHop).getOp());
}
}
else if( currentHop instanceof BinaryOp) {
switch( ((BinaryOp)currentHop).getOp() ) {
case MULT:
case PLUS:
case MINUS:
case MIN:
case MAX:
case AND:
case OR:
case EQUAL:
case NOTEQUAL:
case LESS:
case LESSEQUAL:
case GREATER:
case GREATEREQUAL:
case CBIND:
case RBIND: costs = 1; break;
case INTDIV: costs = 6; break;
case MODULUS: costs = 8; break;
case DIV: costs = 22; break;
case LOG:
case LOG_NZ: costs = 32; break;
case POW: costs = (HopRewriteUtils.isLiteralOfValue(
currentHop.getInput().get(1), 2) ? 1 : 16); break;
case MINUS_NZ:
case MINUS1_MULT: costs = 2; break;
case MOMENT:
int type = (int) (currentHop.getInput().get(1) instanceof LiteralOp ?
HopRewriteUtils.getIntValueSafe((LiteralOp)currentHop.getInput().get(1)) : 2);
switch( type ) {
case 0: costs = 1; break; //count
case 1: costs = 8; break; //mean
case 2: costs = 16; break; //cm2
case 3: costs = 31; break; //cm3
case 4: costs = 51; break; //cm4
case 5: costs = 16; break; //variance
}
break;
case COV: costs = 23; break;
default:
LOG.warn("Cost model not "
+ "implemented yet for: "+((BinaryOp)currentHop).getOp());
}
}
else if( currentHop instanceof TernaryOp) {
switch( ((TernaryOp)currentHop).getOp() ) {
case IFELSE:
case PLUS_MULT:
case MINUS_MULT: costs = 2; break;
case CTABLE: costs = 3; break;
case MOMENT:
int type = (int) (currentHop.getInput().get(1) instanceof LiteralOp ?
HopRewriteUtils.getIntValueSafe((LiteralOp)currentHop.getInput().get(1)) : 2);
switch( type ) {
case 0: costs = 2; break; //count
case 1: costs = 9; break; //mean
case 2: costs = 17; break; //cm2
case 3: costs = 32; break; //cm3
case 4: costs = 52; break; //cm4
case 5: costs = 17; break; //variance
}
break;
case COV: costs = 23; break;
default:
LOG.warn("Cost model not "
+ "implemented yet for: "+((TernaryOp)currentHop).getOp());
}
}
else if( currentHop instanceof NaryOp) {
costs = HopRewriteUtils.isNary(currentHop, Types.OpOpN.MIN, Types.OpOpN.MAX, Types.OpOpN.PLUS) ?
currentHop.getInput().size() : 1;
}
else if( currentHop instanceof ParameterizedBuiltinOp) {
costs = 1;
}
else if( currentHop instanceof IndexingOp) {
costs = 1;
}
else if( currentHop instanceof ReorgOp) {
costs = 1;
}
else if( currentHop instanceof DnnOp) {
switch( ((DnnOp)currentHop).getOp() ) {
case BIASADD:
case BIASMULT:
costs = 2;
default:
LOG.warn("Cost model not "
+ "implemented yet for: "+((DnnOp)currentHop).getOp());
}
}
else if( currentHop instanceof AggBinaryOp) {
//outer product template w/ matrix-matrix
//or row template w/ matrix-vector or matrix-matrix
costs = 2 * currentHop.getInput().get(0).getDim2();
if( currentHop.getInput().get(0).dimsKnown(true) )
costs *= currentHop.getInput().get(0).getSparsity();
}
else if( currentHop instanceof AggUnaryOp) {
switch(((AggUnaryOp)currentHop).getOp()) {
case SUM: costs = 4; break;
case SUM_SQ: costs = 5; break;
case MIN:
case MAX: costs = 1; break;
default:
LOG.warn("Cost model not "
+ "implemented yet for: "+((AggUnaryOp)currentHop).getOp());
}
switch(((AggUnaryOp)currentHop).getDirection()) {
case Col: costs *= Math.max(currentHop.getInput().get(0).getDim1(),1); break;
case Row: costs *= Math.max(currentHop.getInput().get(0).getDim2(),1); break;
case RowCol: costs *= getSize(currentHop.getInput().get(0)); break;
}
}
//scale by current output size in order to correctly reflect
//a mix of row and cell operations in the same fused operator
//(e.g., row template with fused column vector operations)
costs *= getSize(currentHop);
return costs;
}
/**
* Get number of output cells of given hop.
* @param hop for which the number of output cells are found
* @return number of output cells of given hop
*/
private static long getSize(Hop hop) {
return Math.max(hop.getDim1(),1)
* Math.max(hop.getDim2(),1);
}
}