// // AVX2Backend.cpp // MNN // // Created by MNN on 2021/05/16. // Copyright © 2018, Alibaba Group Holding Limited // #include #include "core/SimdHeader.h" #include "AVX2Functions.hpp" #include "AVX2Backend.hpp" #include "core/BufferAllocator.hpp" #include "core/TensorUtils.hpp" #include "backend/cpu/CPURaster.hpp" #include "backend/cpu/CPUReduction.hpp" #include "backend/cpu/CPUSoftmax.hpp" #include "backend/cpu/CPUTensorConvert.hpp" #include "core/OpCommonUtils.hpp" #include "backend/cpu/CPUCast.hpp" extern "C" { void MNNInt8ToUInt8(void* ptr, int count); void MNNUInt8ToInt8(void* ptr, int count); } namespace MNN { bool AVX2Backend::isValid() { return nullptr != AVX2Functions::get(); } AVX2Backend::AVX2Backend(const CPURuntime* runtime, BackendConfig::MemoryMode memory, size_t flags) : CPUBackend(runtime, BackendConfig::Precision_Low, memory, MNN_FORWARD_CPU_EXTENSION, flags) { mCoreFunctions = AVX2Functions::get(); mInt8CoreFunctions = AVX2Functions::getInt8(); mRelatedFunctions = &(mCoreFunctions->int8MatmulRelatedFunctions); } AVX2Backend::~AVX2Backend() { // nothing to do } // TODO: Move to functions static void _CopyC16ToC4_int8(float* dstO, const float* srcO, int channelC4, int area) { auto dst = (int32_t*)dstO; auto src = (int32_t*)srcO; int c8 = channelC4 / 4; int cR = channelC4 % 4; for (int z=0; z 0) { auto s0 = dst + 4 * c8 * area; auto d = src + c8 * area * 4; for (int x=0; x 0) { auto s0 = src + 4 * c8 * area; auto d = dst + c8 * area * 4; for (int x=0; x 0) { auto s0 = src + 4 * c8 * area * 4; auto d = dst + c8 * area * 16; auto v1 = _mm_setzero_ps(); for (int x=0; x 0) { auto s0 = dst + 4 * c8 * area * 4; auto d = src + c8 * area * 16; for (int x=0; x 0) { auto s0 = src + 2 * c8 * area * 4; auto d = dst + c8 * area * 8; auto v1 = _mm_setzero_ps(); for (int x=0; x 0) { auto s0 = dst + 2 * c8 * area * 4; auto d = src + c8 * area * 8; for (int x=0; x 0) { auto s0 = src + 2 * c8 * area * 4; auto d = dst + c8 * area * 8; for (int x=0; x 0) { auto s0 = dst + 2 * c8 * area * 4; auto d = src + c8 * area * 8; for (int x=0; x& inputs, const std::vector& outputs, const MNN::Op* op) { if (op->type() == OpType_ImageProcess) { return CPUBackend::onCreate(inputs, outputs, op); } for (auto t : outputs) { if (t->getType().code != halide_type_float && t->getType().bits != 8) { return nullptr; } if (t->getType().code == halide_type_uint) { return nullptr; } } bool originCreate = OpCommonUtils::opCompabilityForLowp(op, 4); if (originCreate || op->type() == OpType_Softmax || op->type() == OpType_Reduction || op->type() == OpType_ConvInt8 || op->type() == OpType_DepthwiseConvInt8 || op->type() == OpType_FloatToInt8 || op->type() == OpType_Int8ToFloat) { return CPUBackend::onCreate(inputs, outputs, op); } return nullptr; } Backend::MemObj* AVX2Backend::onAcquire(const Tensor* nativeTensor, StorageType storageType) { // arm82 backend tensor data type is fp16 default auto tensor = const_cast(nativeTensor); auto& buffer = tensor->buffer(); auto tensorSize = getTensorSize(nativeTensor, true); // MNN_PRINT("acquire tensor:%p, tensorSize:%d, shape: ", nativeTensor, tensorSize); // nativeTensor->printShape(); auto res = allocBuffer(tensorSize, (Tensor*)nativeTensor, storageType); if (!res) { return nullptr; } // Set mask in device for easy to determine buffer.device = 1; return res; } void AVX2Backend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) const { auto& ib = srcTensor->buffer(); auto& ob = dstTensor->buffer(); std::unique_ptr wrapTensor; if (ib.type.code != halide_type_float && ib.type != halide_type_of()) { CPUBackend::onCopyBuffer(srcTensor, dstTensor); return; } if (ib.dimensions <= 1) { CPUBackend::onCopyBuffer(srcTensor, dstTensor); return; } _resetDynamicMemory(); if (mRuntime->pCurrentStatus != NO_ERROR) { return; } if (getDataType(srcTensor) != getDataType(dstTensor)) { auto dimType = Tensor::CAFFE; switch (TensorUtils::getDescribe(srcTensor)->dimensionFormat) { case MNN_DATA_FORMAT_NCHW: break; case MNN_DATA_FORMAT_NC4HW4: dimType = Tensor::CAFFE_C4; break; case MNN_DATA_FORMAT_NHWC: dimType = Tensor::TENSORFLOW; break; default: break; } auto convertType = CPUCastCreator::FlOAT_TO_INT8; if (getDataType(srcTensor) == DataType_DT_INT8) { convertType = CPUCastCreator::INT8_TO_FlOAT; } wrapTensor.reset(Tensor::createDevice(srcTensor->shape(), dstTensor->getType(), dimType)); auto dstType = getDataType(dstTensor); if (dstType != DataType_DT_FLOAT) { wrapTensor->setType(dstType); } wrapTensor->buffer().host = (uint8_t*)MNNMemoryAllocAlign(getTensorSize(wrapTensor.get()) * wrapTensor->getType().bytes(), MNN_MEMORY_ALIGN_DEFAULT); TensorUtils::getDescribe(wrapTensor.get())->memoryType = Tensor::InsideDescribe::MEMORY_HOST; auto code = CPUCastCreator::cast(srcTensor, wrapTensor.get(), this, convertType); if (NO_ERROR != code) { MNN_ERROR("Error in CPUBackend::onCopyBuffer:cast\n"); } srcTensor = wrapTensor.get(); } else if (srcTensor->getType() != dstTensor->getType()) { MNN_ERROR("Input type not match session's tensor\n"); return; } auto source = TensorUtils::getDescribe(srcTensor)->dimensionFormat; auto dest = TensorUtils::getDescribe(dstTensor)->dimensionFormat; auto srcType = MNN_FORWARD_CPU; if (ib.device != 0) { srcType = MNN_FORWARD_CPU_EXTENSION; } auto dstType = MNN_FORWARD_CPU; if (ob.device != 0) { dstType = MNN_FORWARD_CPU_EXTENSION; } if (srcType == dstType) { if(srcType == MNN_FORWARD_CPU_EXTENSION) { CPUTensorConverter::convert(srcTensor, dstTensor, mCoreFunctions); } else { CPUTensorConverter::convert(srcTensor, dstTensor, MNNGetCoreFunctions()); } return; } if (source != MNN_DATA_FORMAT_NC4HW4 && dest != MNN_DATA_FORMAT_NC4HW4) { CPUTensorConverter::convert(srcTensor, dstTensor, mCoreFunctions); return; } if (source == MNN_DATA_FORMAT_NC4HW4 && dest == MNN_DATA_FORMAT_NC4HW4) { auto outF = _CopyC8ToC4; auto inF = _CopyC4ToC8; auto obBytes = CPUBackend::getBytes(this, dstTensor); if (obBytes == 1) { outF = _CopyC8ToC4_int8; inF = _CopyC4ToC8_int8; } if (mCoreFunctions->pack == 16) { outF = _CopyC16ToC4; inF = _CopyC4ToC16; if (obBytes == 1) { outF = _CopyC16ToC4_int8; inF = _CopyC4ToC16_int8; } } // NC4HW4 <-> NC8HW8 if (1 == srcTensor->dimensions()) { ::memcpy(dstTensor->host(), srcTensor->host(), srcTensor->length(0) * srcTensor->getType().bytes()); return; } auto dims = CPUTensorConverter::splitDimensions(srcTensor->buffer(), source); int area = std::get<1>(dims) * std::get<0>(dims); int channel = std::get<2>(dims); auto c4 = UP_DIV(channel, 4); if (srcType == MNN_FORWARD_CPU_EXTENSION) { outF(dstTensor->host(), srcTensor->host(), c4, area); } else { inF(dstTensor->host(), srcTensor->host(), c4, area); } return; } if (source == MNN_DATA_FORMAT_NC4HW4) { if (srcType == MNN_FORWARD_CPU_EXTENSION) { CPUTensorConverter::convert(srcTensor, dstTensor, mCoreFunctions); } else { CPUTensorConverter::convert(srcTensor, dstTensor, MNNGetCoreFunctions()); } return; } if (dest == MNN_DATA_FORMAT_NC4HW4) { if (dstType == MNN_FORWARD_CPU_EXTENSION) { CPUTensorConverter::convert(srcTensor, dstTensor, mCoreFunctions); } else { CPUTensorConverter::convert(srcTensor, dstTensor, MNNGetCoreFunctions()); } return; } MNN_ASSERT(false); return; } } // namespace MNN