size_t SymbolTable::map_operand(bh_instruction& instr, size_t operand_idx) { size_t arg_idx = ++(nsymbols_); // Candidate arg_idx if not reused if (bh_is_constant(&instr.operand[operand_idx])) { // Constants if (BH_R123 != instr.constant.type) { // Regular constants table_[arg_idx].const_data = &(instr.constant.value); table_[arg_idx].etype = bhtype_to_etype(instr.constant.type); } else { // "Special" for BH_R123 table_[arg_idx].etype = UINT64; if (1 == operand_idx) { table_[arg_idx].const_data = &(instr.constant.value.r123.start); } else if (2 == operand_idx) { table_[arg_idx].const_data = &(instr.constant.value.r123.key); } else { throw runtime_error("THIS SHOULD NEVER HAPPEN!"); } } table_[arg_idx].data = &table_[arg_idx].const_data; table_[arg_idx].nelem = 1; table_[arg_idx].ndim = 1; table_[arg_idx].start = 0; table_[arg_idx].shape = instr.operand[operand_idx].shape; table_[arg_idx].shape[0] = 1; table_[arg_idx].stride = instr.operand[operand_idx].shape; table_[arg_idx].stride[0] = 0; table_[arg_idx].layout = SCALAR_CONST; table_[arg_idx].base = NULL; } else { table_[arg_idx].const_data= NULL; table_[arg_idx].data = &(bh_base_array(&instr.operand[operand_idx])->data); table_[arg_idx].etype = bhtype_to_etype(bh_base_array(&instr.operand[operand_idx])->type); table_[arg_idx].nelem = bh_base_array(&instr.operand[operand_idx])->nelem; table_[arg_idx].ndim = instr.operand[operand_idx].ndim; table_[arg_idx].start = instr.operand[operand_idx].start; table_[arg_idx].shape = instr.operand[operand_idx].shape; table_[arg_idx].stride = instr.operand[operand_idx].stride; table_[arg_idx].layout = determine_layout(table_[arg_idx]); table_[arg_idx].base = instr.operand[operand_idx].base; } // // Reuse operand identifiers: Detect if we have seen it before and reuse the name. // This is done by comparing the currently investigated operand (arg_idx) // with all other operands in the current scope [1,arg_idx[ // Do remember that 0 is is not a valid operand and we therefore index from 1. // Also we do not want to compare with selv, that is when i == arg_idx. for(size_t i=1; i<arg_idx; ++i) { if (!equivalent(table_[i], table_[arg_idx])) { continue; // Not equivalent, continue search. } // Found one! Use it instead of the incremented identifier. --nsymbols_; arg_idx = i; break; } return arg_idx; }
/* Communicate array data such that the processes can apply local computation. * NB: The process that owns the data and the process where the data is located * must both call this function. * * @chunk The local array chunk to communicate * @sending_rank The rank of the sending process * @receiving_rank The rank of the receiving process, e.g. the process that should * apply the computation */ void comm_array_data(const bh_view &chunk, int sending_rank, int receiving_rank) { // printf("comm_array_data %d => %d: ", sending_rank, receiving_rank); // bh_view v = chunk; // bh_pprint_array(&v); //Check if communication is even necessary if(sending_rank == receiving_rank) return; if(pgrid_myrank == receiving_rank) { //Schedule the receive message batch_schedule_comm(0, sending_rank, chunk); } else if(pgrid_myrank == sending_rank) { //We need to copy the local array view into a base array buffer. bh_view tmp_view = chunk; tmp_view.base = tmp_get_ary(bh_base_array(&chunk)->type, bh_nelements_nbcast(&chunk)); tmp_view.start = 0; //Set a contiguous row-major stride while preserving the zero-strided //dimensions (i.e. preserving broadcasted dimensions). bh_intp s = 1; for(bh_intp i=chunk.ndim-1; i >= 0; --i) { if(tmp_view.stride[i] > 0) { tmp_view.stride[i] = s; s *= tmp_view.shape[i]; } } //Tell the VEM to do the data copy. bh_view ops[] = {tmp_view, chunk}; batch_schedule_inst(BH_IDENTITY, ops); //Schedule the send message batch_schedule_comm(1, receiving_rank, tmp_view); //Cleanup the local arrays batch_schedule_inst_on_base(BH_FREE, bh_base_array(&tmp_view)); batch_schedule_inst_on_base(BH_DISCARD, bh_base_array(&tmp_view)); } }
/* Implements matrix multiplication */ bh_error bh_matmul(bh_instruction *instr, void* arg) { bh_view *C = &instr->operand[0]; bh_view *A = &instr->operand[1]; bh_view *B = &instr->operand[2]; //Make sure that the arrays memory are allocated. if(bh_data_malloc(A->base) != BH_SUCCESS) return BH_OUT_OF_MEMORY; if(bh_data_malloc(B->base) != BH_SUCCESS) return BH_OUT_OF_MEMORY; if(bh_data_malloc(C->base) != BH_SUCCESS) return BH_OUT_OF_MEMORY; switch (bh_base_array(C)->type) { case BH_INT8: return do_matmul<bh_int8>(A, B, C); case BH_INT16: return do_matmul<bh_int16>(A, B, C); case BH_INT32: return do_matmul<bh_int32>(A, B, C); case BH_INT64: return do_matmul<bh_int64>(A, B, C); case BH_UINT8: return do_matmul<bh_uint8>(A, B, C); case BH_UINT16: return do_matmul<bh_uint16>(A, B, C); case BH_UINT32: return do_matmul<bh_uint32>(A, B, C); case BH_UINT64: return do_matmul<bh_uint64>(A, B, C); case BH_FLOAT32: return do_matmul<bh_float32>(A, B, C); case BH_FLOAT64: return do_matmul<bh_float64>(A, B, C); case BH_COMPLEX64: return do_matmul<std::complex<float> >(A, B, C); case BH_COMPLEX128: return do_matmul<std::complex<double> >(A, B, C); default: return BH_TYPE_NOT_SUPPORTED; } }
int main() { dispatch_msg *msg; timing_init(); //Initiate the process grid pgrid_init(); while(1) { //Receive the dispatch message from the master-process dispatch_reset(); dispatch_recv(&msg); //Handle the message switch(msg->type) { case BH_CLUSTER_DISPATCH_INIT: { char *name = msg->payload; check_error(exec_init(name),__FILE__,__LINE__); break; } case BH_CLUSTER_DISPATCH_SHUTDOWN: { check_error(exec_shutdown(),__FILE__,__LINE__); return 0; } case BH_CLUSTER_DISPATCH_EXTMETHOD: { bh_opcode opcode = *((bh_opcode *)msg->payload); char *name = msg->payload+sizeof(bh_opcode); check_error(exec_extmethod(name, opcode),__FILE__,__LINE__); break; } case BH_CLUSTER_DISPATCH_EXEC: { //Get the size of the the serialized BhIR bh_intp bhir_size = *((bh_intp*) msg->payload); //Deserialize the BhIR bh_ir bhir = bh_ir(((char*)msg->payload)+sizeof(bh_intp), bhir_size); //The number of new arrays bh_intp *noa = (bh_intp *)(((char*)msg->payload)+sizeof(bh_intp)+bhir_size); //The list of new arrays dispatch_array *darys = (dispatch_array*)(noa+1); //number of new arrays //Insert the new array into the array store and the array maps std::stack<bh_base*> base_darys; for(bh_intp i=0; i < *noa; ++i) { bh_base *ary = dispatch_new_slave_array(&darys[i].ary, darys[i].id); base_darys.push(ary); } //Receive the dispatched array-data from the master-process dispatch_array_data(base_darys); //Update all instruction to reference local arrays for(uint64_t i=0; i < bhir.instr_list.size(); ++i) { bh_instruction *inst = &bhir.instr_list[i]; int nop = bh_noperands(inst->opcode); bh_view *ops = bh_inst_operands(inst); //Convert all instructon operands for(bh_intp j=0; j<nop; ++j) { if(bh_is_constant(&ops[j])) continue; bh_base *base = bh_base_array(&ops[j]); assert(dispatch_slave_exist((bh_intp)base)); bh_base_array(&ops[j]) = dispatch_master2slave((bh_intp)base); } } check_error(exec_execute(&bhir),__FILE__,__LINE__); break; } default: fprintf(stderr, "[VEM-CLUSTER] Slave (rank %d) " "received unknown message type\n", pgrid_myrank); MPI_Abort(MPI_COMM_WORLD,BH_ERROR); } } timing_finalize(); return BH_SUCCESS; }