/* * ****************************************************************************** * * * * * * This program and the accompanying materials are made available under the * * terms of the Apache License, Version 2.0 which is available at * * https://www.apache.org/licenses/LICENSE-2.0. * * * * See the NOTICE file distributed with this work for additional * * information regarding copyright ownership. * * 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. * * * * SPDX-License-Identifier: Apache-2.0 * ***************************************************************************** */ // // @author Yurii Shyrma (iuriish@yahoo.com), created on 20.04.2018 // #include #include #include #include #include #include #include #include #include "execution/cuda/LaunchDims.h" namespace sd { namespace ops { namespace helpers { /////////////////////////////////////////////////////////////////// template SD_KERNEL static void invertPermutationCuda(const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo) { const T* x = reinterpret_cast(vx); T* z = reinterpret_cast(vz); __shared__ LongType len, totalThreads; if (threadIdx.x == 0) { len = shape::length(xShapeInfo); totalThreads = gridDim.x * blockDim.x; } __syncthreads(); const auto tid = blockIdx.x * blockDim.x + threadIdx.x; LongType xCoords[SD_MAX_RANK]; LongType zCoords[SD_MAX_RANK]; LongType xOffset; LongType zOffset; for (LongType i = tid; i < len; i += totalThreads) { INDEX2COORDS(i, shape::rank(xShapeInfo), shape::shapeOf(xShapeInfo), xCoords); COORDS2INDEX(shape::rank(xShapeInfo), shape::stride(xShapeInfo), xCoords, xOffset); const LongType index = x[xOffset]; INDEX2COORDS(index, shape::rank(zShapeInfo), shape::shapeOf(zShapeInfo), zCoords); COORDS2INDEX(shape::rank(zShapeInfo), shape::stride(zShapeInfo), zCoords, zOffset); z[zOffset] = i; } } /////////////////////////////////////////////////////////////////// template SD_HOST static void invertPermutationCudaLauncher(const int blocksPerGrid, const int threadsPerBlock, const int sharedMemory, const cudaStream_t* stream, const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo) { invertPermutationCuda<<>>(vx, xShapeInfo, vz, zShapeInfo); sd::DebugHelper::checkErrorCode(const_cast(stream), "invertPermutationCuda failed"); } //////////////////////////////////////////////////////////////////////// void invertPermutation(LaunchContext* context, NDArray& input, NDArray& output) { dim3 invertPermuteDims = invertPermutationDims(input.lengthOf()); PointersManager manager(context, "invertPermutation"); NDArray::prepareSpecialUse({&output}, {&input}); BUILD_SINGLE_SELECTOR(input.dataType(), invertPermutationCudaLauncher, (invertPermuteDims.x, invertPermuteDims.y, invertPermuteDims.z,context->getCudaStream(), input.specialBuffer(), input.specialShapeInfo(), output.specialBuffer(), output.specialShapeInfo()), SD_COMMON_TYPES); NDArray::registerSpecialUse({&output}, {&input}); manager.synchronize(); } ////////////////////////////////////////////////////////////////////////// template SD_KERNEL static void traceCuda(const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, const LongType diagLen) { const auto x = reinterpret_cast(vx); auto z = reinterpret_cast(vz); __shared__ T sharedMem[SD_CUDA_BLOCK_SIZE]; // Shared variables for ranks, shapes, and strides __shared__ sd::LongType xRank, zRank; __shared__ const sd::LongType* xShapePtr; __shared__ const sd::LongType* xStridePtr; __shared__ const sd::LongType* zShapePtr; __shared__ const sd::LongType* zStridePtr; __shared__ LongType xLen, zLen; // Cache all shape-related values in thread 0 if (threadIdx.x == 0) { xRank = shape::rank(xShapeInfo); zRank = shape::rank(zShapeInfo); xShapePtr = shape::shapeOf(xShapeInfo); xStridePtr = shape::stride(xShapeInfo); zShapePtr = shape::shapeOf(zShapeInfo); zStridePtr = shape::stride(zShapeInfo); xLen = shape::length(xShapeInfo); zLen = shape::length(zShapeInfo); // corresponds to number of matrices } __syncthreads(); LongType coords[SD_MAX_RANK]; // One block per each element of z, that is per each matrix for (LongType m = blockIdx.x; m < zLen; m += gridDim.x) { INDEX2COORDS(m, zRank, zShapePtr, coords); LongType zOffset; COORDS2INDEX(zRank, zStridePtr, coords, zOffset); sharedMem[threadIdx.x] = 0; for (LongType i = threadIdx.x; i < diagLen; i += blockDim.x) { coords[zRank] = coords[zRank + 1] = i; LongType xOffset; COORDS2INDEX(xRank, xStridePtr, coords, xOffset); sharedMem[threadIdx.x] += x[xOffset]; } __syncthreads(); // Aggregate sum for (LongType activeThreads = blockDim.x / 2; activeThreads > 0; activeThreads /= 2) { if (threadIdx.x < activeThreads) { sharedMem[threadIdx.x] += sharedMem[threadIdx.x + activeThreads]; } __syncthreads(); } if (threadIdx.x == 0) { z[zOffset] = *sharedMem; } __syncthreads(); } } /////////////////////////////////////////////////////////////////// template static void traceCudaLauncher(const int blocksPerGrid, const int threadsPerBlock, const int sharedMem, const cudaStream_t* stream, const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, const LongType diagLen) { traceCuda<<>>(vx, xShapeInfo, vz, zShapeInfo, diagLen); sd::DebugHelper::checkErrorCode(const_cast(stream), "traceCuda failed"); } /////////////////////////////////////////////////////////////////// void trace(LaunchContext* context, NDArray& input, NDArray& output) { PointersManager manager(context, "trace"); const LongType diagLen = input.sizeAt(-1) < input.sizeAt(-2) ? input.sizeAt(-1) : input.sizeAt(-2); const int threadsPerBlock = SD_CUDA_BLOCK_SIZE; const int blocksPerGrid = (output.lengthOf() + threadsPerBlock - 1) / threadsPerBlock; const int sharedMem = 1024; dim3 traceDims2 = traceDims(output.lengthOf()); NDArray::prepareSpecialUse({&output}, {&input}); BUILD_SINGLE_SELECTOR(input.dataType(), traceCudaLauncher, (traceDims2.y, traceDims2.x, traceDims2.z, context->getCudaStream(), input.specialBuffer(), input.specialShapeInfo(), output.specialBuffer(), output.specialShapeInfo(), diagLen), SD_COMMON_TYPES); NDArray::registerSpecialUse({&output}, {&input}); manager.synchronize(); } /////////////////////////////////////////////////////////////////// template SD_KERNEL static void triuBPCuda(const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, const int diag) { const auto x = reinterpret_cast(vx); // gradO auto z = reinterpret_cast(vz); // gradI __shared__ int rank, areSameOffsets; __shared__ LongType len, totalThreads; // xLen = zLen // Cache shape information __shared__ const sd::LongType* xShapePtr; __shared__ const sd::LongType* zShapePtr; __shared__ const sd::LongType* xStridePtr; __shared__ const sd::LongType* zStridePtr; __shared__ int xRank, zRank; if (threadIdx.x == 0) { areSameOffsets = shape::haveSameShapeAndStrides(xShapeInfo, zShapeInfo); rank = shape::rank(xShapeInfo); len = shape::length(zShapeInfo); totalThreads = gridDim.x * blockDim.x; // Cache shape information xRank = shape::rank(xShapeInfo); zRank = shape::rank(zShapeInfo); xShapePtr = shape::shapeOf(xShapeInfo); zShapePtr = shape::shapeOf(zShapeInfo); xStridePtr = shape::stride(xShapeInfo); zStridePtr = shape::stride(zShapeInfo); } __syncthreads(); LongType coords[SD_MAX_RANK]; const LongType tid = blockIdx.x * blockDim.x + threadIdx.x; for (LongType i = tid; i < len; i += totalThreads) { INDEX2COORDS(i, zRank, zShapePtr, coords); sd::LongType zOffset; COORDS2INDEX(zRank, zStridePtr, coords, zOffset); if ((coords[rank - 2] + diag > coords[rank - 1])) // row + diag > col z[zOffset] = 0; else { if (areSameOffsets) { z[zOffset] = x[zOffset]; } else { sd::LongType xOffset; COORDS2INDEX(xRank, xStridePtr, coords, xOffset); z[zOffset] = x[xOffset]; } } } } /////////////////////////////////////////////////////////////////// template static void triuBPCudaLauncher(const int blocksPerGrid, const int threadsPerBlock, const int sharedMem, const cudaStream_t* stream, const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, const int diag) { triuBPCuda<<>>(vx, xShapeInfo, vz, zShapeInfo, diag); sd::DebugHelper::checkErrorCode(const_cast(stream), "triuBP failed"); } /////////////////////////////////////////////////////////////////// void triuBP(LaunchContext* context, NDArray& input, NDArray& gradO, NDArray& gradI, const int diagonal) { const int threadsPerBlock = SD_MAX_NUM_THREADS / 4; const int blocksPerGrid = (gradO.lengthOf() + threadsPerBlock - 1) / threadsPerBlock; const int sharedMem = threadsPerBlock * sizeof(LongType) * gradO.rankOf() + 128; dim3 triuDims2 = triuDims(gradO.lengthOf(),gradO.rankOf()); PointersManager manager(context, "triuBP"); NDArray::prepareSpecialUse({&gradI}, {&gradO}); BUILD_SINGLE_SELECTOR(gradI.dataType(), triuBPCudaLauncher, (triuDims2.y, triuDims2.x, triuDims2.z, context->getCudaStream(), gradO.specialBuffer(), gradO.specialShapeInfo(), gradI.specialBuffer(), gradI.specialShapeInfo(), diagonal), SD_COMMON_TYPES); NDArray::registerSpecialUse({&gradI}, {&gradO}); manager.synchronize(); } /////////////////////////////////////////////////////////////////// template SD_KERNEL static void tileBPCuda(const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, LongType* globMem) { const auto x = reinterpret_cast(vx); // gradO auto z = reinterpret_cast(vz); // gradI __shared__ int xRank, zRank; __shared__ LongType numOfXOffsets, zLen, totalThreads; // Cache shape information __shared__ const sd::LongType* zShapePtr; __shared__ const sd::LongType* zStridePtr; if (threadIdx.x == 0) { xRank = shape::rank(zShapeInfo); zRank = shape::rank(zShapeInfo); zLen = shape::length(zShapeInfo); numOfXOffsets = shape::length(xShapeInfo) / zLen; totalThreads = gridDim.x * blockDim.x; // Cache shape information zShapePtr = shape::shapeOf(zShapeInfo); zStridePtr = shape::stride(zShapeInfo); } __syncthreads(); const auto tid = blockIdx.x * blockDim.x + threadIdx.x; LongType memBuff[SD_MAX_RANK * 2]; auto xOffsets = globMem + tid * numOfXOffsets; for (LongType i = tid; i < zLen; i += totalThreads) { LongType zCoords[SD_MAX_RANK]; LongType zOffset; INDEX2COORDS(i, zRank, zShapePtr, zCoords); COORDS2INDEX(zRank, zStridePtr, zCoords, zOffset); shape::outerArrayOffsets(xOffsets, i, xShapeInfo, zShapeInfo, memBuff, nullptr); z[zOffset] = x[xOffsets[0]]; // first offset for (LongType j = 1; j < numOfXOffsets; ++j) // rest offsets z[zOffset] += x[xOffsets[j]]; } } /////////////////////////////////////////////////////////////////// template static void tileBPCudaLauncher(const int blocksPerGrid, const int threadsPerBlock, const int sharedMem, const cudaStream_t* stream, const void* vx, const LongType* xShapeInfo, void* vz, const LongType* zShapeInfo, LongType* globMem) { tileBPCuda<<>>(vx, xShapeInfo, vz, zShapeInfo, globMem); sd::DebugHelper::checkErrorCode(const_cast(stream), "tileBPCudaLauncher failed"); } ////////////////////////////////////////////////////////////////////////// void tileBP(LaunchContext* context, NDArray gradO /*input*/, NDArray& gradI /*output*/, const std::vector reps) { auto grad0Shape = gradO.getShapeAsVector(); NDArray memBuff( 'c', grad0Shape, INT64, context); // empty auxiliary array for storing device memory which will be used in kernel calculations dim3 tileDims2 = tileDims(gradI.lengthOf(),gradI.rankOf()); PointersManager manager(context, "tileBP"); NDArray::prepareSpecialUse({&gradI}, {&gradO, &memBuff}); BUILD_SINGLE_SELECTOR(gradI.dataType(), tileBPCudaLauncher, (tileDims2.y, tileDims2.x, tileDims2.z, context->getCudaStream(), gradO.specialBuffer(), gradO.specialShapeInfo(), gradI.specialBuffer(), gradI.specialShapeInfo(), reinterpret_cast(memBuff.specialBuffer())), SD_FLOAT_TYPES); NDArray::registerSpecialUse({&gradI}, {&gradO, &memBuff}); manager.synchronize(); } ////////////////////////////////////////////////////////////////////////// void eye(LaunchContext* context, NDArray& output) { output.setIdentity(); } } // namespace helpers } // namespace ops } // namespace sd