nd4j-backends/nd4j-backend-impls/nd4j-cuda/src/main/java/org/nd4j/jita/constant/ProtectedCudaConstantHandler.java
@Override
    public synchronized long moveToConstantSpace(DataBuffer dataBuffer) {
        // now, we move things to constant memory
        Integer deviceId = AtomicAllocator.getInstance().getDeviceId();
        ensureMaps(deviceId);

        AllocationPoint point = AtomicAllocator.getInstance().getAllocationPoint(dataBuffer);

        long requiredMemoryBytes = AllocationUtils.getRequiredMemory(point.getShape());
        //logger.info("shape: " + point.getShape());
        // and release device memory :)

        long currentOffset = constantOffsets.get(deviceId).get();
        CudaContext context = (CudaContext) AtomicAllocator.getInstance().getDeviceContext().getContext();
        if (currentOffset + requiredMemoryBytes >= MAX_CONSTANT_LENGTH || requiredMemoryBytes > MAX_BUFFER_LENGTH) {
            if (point.getAllocationStatus() == AllocationStatus.HOST
                            && CudaEnvironment.getInstance().getConfiguration().getMemoryModel() == Configuration.MemoryModel.DELAYED) {
                AtomicAllocator.getInstance().getMemoryHandler().alloc(AllocationStatus.DEVICE, point, point.getShape(),
                                false);
            }

            val profD = PerformanceTracker.getInstance().helperStartTransaction();

            if (NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyAsync(point.getPointers().getDevicePointer(), point.getPointers().getHostPointer(),
                            requiredMemoryBytes, 1, context.getSpecialStream()) == 0) {
                throw new ND4JIllegalStateException("memcpyAsync failed");
            }
            flowController.commitTransfer(context.getSpecialStream());

            PerformanceTracker.getInstance().helperRegisterTransaction(point.getDeviceId(), profD, point.getNumberOfBytes(), MemcpyDirection.HOST_TO_DEVICE);

            point.setConstant(true);
            point.tickDeviceWrite();
            point.tickHostRead();
            point.setDeviceId(deviceId);

            protector.persistDataBuffer(dataBuffer);

            return 0;
        }

        long bytes = requiredMemoryBytes;
        // hack for misalignment avoidance for 16bit data opType
        if (dataBuffer.dataType() == DataBuffer.Type.HALF) {
            if (bytes % 4 != 0) {
                bytes += 2;
            }
        } else if (Nd4j.dataType() == DataBuffer.Type.DOUBLE || dataBuffer.dataType() == DataBuffer.Type.LONG) {
            // for double data opType, we must be assured, that all DOUBLE pointers are starting from even addresses, to avoid banks spills
            long div = bytes / 4;
            if (div % 2 != 0)
                bytes += 4;

            // for possible changes of dtype in the same jvm, we skip few bytes in constant memory
            div = currentOffset / 4;
            while (div % 2 != 0) {
                currentOffset = constantOffsets.get(deviceId).addAndGet(4);
                div = currentOffset / 4;

                // just break out, if we're stepped beyond constant memory space
                if (currentOffset > MAX_CONSTANT_LENGTH)
                    break;
            }
        }

        currentOffset = constantOffsets.get(deviceId).getAndAdd(bytes);

        if (currentOffset >= MAX_CONSTANT_LENGTH) {
            if (point.getAllocationStatus() == AllocationStatus.HOST
                            && CudaEnvironment.getInstance().getConfiguration().getMemoryModel() == Configuration.MemoryModel.DELAYED) {
                AtomicAllocator.getInstance().getMemoryHandler().alloc(AllocationStatus.DEVICE, point, point.getShape(),
                                false);
            }

            val profD = PerformanceTracker.getInstance().helperStartTransaction();

            if (NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyAsync(point.getPointers().getDevicePointer(), point.getPointers().getHostPointer(),
                            requiredMemoryBytes, 1, context.getSpecialStream()) == 0) {
                throw new ND4JIllegalStateException("memcpyAsync failed");
            }
            flowController.commitTransfer(context.getSpecialStream());

            PerformanceTracker.getInstance().helperRegisterTransaction(point.getDeviceId(), profD, point.getNumberOfBytes(), MemcpyDirection.HOST_TO_DEVICE);

            point.setConstant(true);
            point.tickDeviceWrite();
            point.tickHostRead();
            point.setDeviceId(deviceId);

            protector.persistDataBuffer(dataBuffer);

            return 0;
        }



        NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyConstantAsync(currentOffset, point.getPointers().getHostPointer(), requiredMemoryBytes, 1,
                        context.getSpecialStream());
        flowController.commitTransfer(context.getSpecialStream());

        long cAddr = deviceAddresses.get(deviceId).address() + currentOffset;

        //if (resetHappened)
        //    logger.info("copying to constant: {}, bufferLength: {}, bufferDtype: {}, currentOffset: {}, currentAddres: {}", requiredMemoryBytes, dataBuffer.length(), dataBuffer.dataType(), currentOffset, cAddr);

        point.setAllocationStatus(AllocationStatus.CONSTANT);
        point.getPointers().setDevicePointer(new CudaPointer(cAddr));
        point.setConstant(true);
        point.tickDeviceWrite();
        point.setDeviceId(deviceId);
        point.tickHostRead();


        protector.persistDataBuffer(dataBuffer);

        return cAddr;
    }
@Override
    public synchronized long moveToConstantSpace(DataBuffer dataBuffer) {
        // now, we move things to constant memory
        Integer deviceId = AtomicAllocator.getInstance().getDeviceId();
        ensureMaps(deviceId);

        AllocationPoint point = AtomicAllocator.getInstance().getAllocationPoint(dataBuffer);

        long requiredMemoryBytes = AllocationUtils.getRequiredMemory(point.getShape());
        //logger.info("shape: " + point.getShape());
        // and release device memory :)

        long currentOffset = constantOffsets.get(deviceId).get();
        CudaContext context = (CudaContext) AtomicAllocator.getInstance().getDeviceContext().getContext();
        if (currentOffset + requiredMemoryBytes >= MAX_CONSTANT_LENGTH || requiredMemoryBytes > MAX_BUFFER_LENGTH) {
            if (point.getAllocationStatus() == AllocationStatus.HOST
                            && CudaEnvironment.getInstance().getConfiguration().getMemoryModel() == Configuration.MemoryModel.DELAYED) {
                AtomicAllocator.getInstance().getMemoryHandler().alloc(AllocationStatus.DEVICE, point, point.getShape(),
                                false);
            }

            val profD = PerformanceTracker.getInstance().helperStartTransaction();

            if (NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyAsync(point.getPointers().getDevicePointer(), point.getPointers().getHostPointer(),
                            requiredMemoryBytes, 1, context.getSpecialStream()) == 0) {
                throw new ND4JIllegalStateException("memcpyAsync failed");
            }
            flowController.commitTransfer(context.getSpecialStream());

            PerformanceTracker.getInstance().helperRegisterTransaction(point.getDeviceId(), profD, point.getNumberOfBytes(), MemcpyDirection.HOST_TO_DEVICE);

            point.setConstant(true);
            point.tickDeviceWrite();
            point.tickHostRead();
            point.setDeviceId(deviceId);

            protector.persistDataBuffer(dataBuffer);

            return 0;
        }

        long bytes = requiredMemoryBytes;
        // hack for misalignment avoidance for 16bit data opType
        if (dataBuffer.dataType() == DataBuffer.Type.HALF) {
            if (bytes % 4 != 0) {
                bytes += 2;
            }
        } else if (Nd4j.dataType() == DataBuffer.Type.DOUBLE || dataBuffer.dataType() == DataBuffer.Type.LONG) {
            // for double data opType, we must be assured, that all DOUBLE pointers are starting from even addresses, to avoid banks spills
            long div = bytes / 4;
            if (div % 2 != 0)
                bytes += 4;

            // for possible changes of dtype in the same jvm, we skip few bytes in constant memory
            div = currentOffset / 4;
            while (div % 2 != 0) {
                currentOffset = constantOffsets.get(deviceId).addAndGet(4);
                div = currentOffset / 4;

                // just break out, if we're stepped beyond constant memory space
                if (currentOffset > MAX_CONSTANT_LENGTH)
                    break;
            }
        }

        currentOffset = constantOffsets.get(deviceId).getAndAdd(bytes);

        if (currentOffset >= MAX_CONSTANT_LENGTH) {
            if (point.getAllocationStatus() == AllocationStatus.HOST
                            && CudaEnvironment.getInstance().getConfiguration().getMemoryModel() == Configuration.MemoryModel.DELAYED) {
                AtomicAllocator.getInstance().getMemoryHandler().alloc(AllocationStatus.DEVICE, point, point.getShape(),
                                false);
            }

            val profD = PerformanceTracker.getInstance().helperStartTransaction();

            if (NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyAsync(point.getPointers().getDevicePointer(), point.getPointers().getHostPointer(),
                            requiredMemoryBytes, 1, context.getSpecialStream()) == 0) {
                throw new ND4JIllegalStateException("memcpyAsync failed");
            }
            flowController.commitTransfer(context.getSpecialStream());

            PerformanceTracker.getInstance().helperRegisterTransaction(point.getDeviceId(), profD, point.getNumberOfBytes(), MemcpyDirection.HOST_TO_DEVICE);

            point.setConstant(true);
            point.tickDeviceWrite();
            point.tickHostRead();
            point.setDeviceId(deviceId);

            protector.persistDataBuffer(dataBuffer);

            return 0;
        }



        NativeOpsHolder.getInstance().getDeviceNativeOps().memcpyConstantAsync(currentOffset, point.getPointers().getHostPointer(), requiredMemoryBytes, 1,
                        context.getSpecialStream());
        flowController.commitTransfer(context.getSpecialStream());

        long cAddr = deviceAddresses.get(deviceId).address() + currentOffset;

        //if (resetHappened)
        //    logger.info("copying to constant: {}, bufferLength: {}, bufferDtype: {}, currentOffset: {}, currentAddres: {}", requiredMemoryBytes, dataBuffer.length(), dataBuffer.dataType(), currentOffset, cAddr);

        point.setAllocationStatus(AllocationStatus.CONSTANT);
        point.getPointers().setDevicePointer(new CudaPointer(cAddr));
        point.setConstant(true);
        point.tickDeviceWrite();
        point.setDeviceId(deviceId);
        point.tickHostRead();


        protector.persistDataBuffer(dataBuffer);

        return cAddr;
    }
@ Override public synchronized long moveToConstantSpace ( DataBuffer dataBuffer ) { // now, we move things to constant memory Integer deviceId = AtomicAllocator . getInstance ( ) . getDeviceId ( ) ; ensureMaps ( deviceId ) ; AllocationPoint point = AtomicAllocator . getInstance ( ) . getAllocationPoint ( dataBuffer ) ; long requiredMemoryBytes = AllocationUtils . getRequiredMemory ( point . getShape ( ) ) ; //logger.info("shape: " + point.getShape()); // and release device memory :) long currentOffset = constantOffsets . get ( deviceId ) . get ( ) ; CudaContext context = ( CudaContext ) AtomicAllocator . getInstance ( ) . getDeviceContext ( ) . getContext ( ) ; if ( currentOffset + requiredMemoryBytes >= MAX_CONSTANT_LENGTH || requiredMemoryBytes > MAX_BUFFER_LENGTH ) { if ( point . getAllocationStatus ( ) == AllocationStatus . HOST && CudaEnvironment . getInstance ( ) . getConfiguration ( ) . getMemoryModel ( ) == Configuration . MemoryModel . DELAYED ) { AtomicAllocator . getInstance ( ) . getMemoryHandler ( ) . alloc ( AllocationStatus . DEVICE , point , point . getShape ( ) , false ) ; } val profD = PerformanceTracker . getInstance ( ) . helperStartTransaction ( ) ; if ( NativeOpsHolder . getInstance ( ) . getDeviceNativeOps ( ) . memcpyAsync ( point . getPointers ( ) . getDevicePointer ( ) , point . getPointers ( ) . getHostPointer ( ) , requiredMemoryBytes , 1 , context . getSpecialStream ( ) ) == 0 ) { throw new ND4JIllegalStateException ( "memcpyAsync failed" ) ; } flowController . commitTransfer ( context . getSpecialStream ( ) ) ; PerformanceTracker . getInstance ( ) . helperRegisterTransaction ( point . getDeviceId ( ) , profD , point . getNumberOfBytes ( ) , MemcpyDirection . HOST_TO_DEVICE ) ; point . setConstant ( true ) ; point . tickDeviceWrite ( ) ; point . tickHostRead ( ) ; point . setDeviceId ( deviceId ) ; protector . persistDataBuffer ( dataBuffer ) ; return 0 ; } long bytes = requiredMemoryBytes ; // hack for misalignment avoidance for 16bit data opType if ( dataBuffer . dataType ( ) == DataBuffer . Type . HALF ) { if ( bytes % 4 != 0 ) { bytes += 2 ; } } else if ( Nd4j . dataType ( ) == DataBuffer . Type . DOUBLE || dataBuffer . dataType ( ) == DataBuffer . Type . LONG ) { // for double data opType, we must be assured, that all DOUBLE pointers are starting from even addresses, to avoid banks spills long div = bytes / 4 ; if ( div % 2 != 0 ) bytes += 4 ; // for possible changes of dtype in the same jvm, we skip few bytes in constant memory div = currentOffset / 4 ; while ( div % 2 != 0 ) { currentOffset = constantOffsets . get ( deviceId ) . addAndGet ( 4 ) ; div = currentOffset / 4 ; // just break out, if we're stepped beyond constant memory space if ( currentOffset > MAX_CONSTANT_LENGTH ) break ; } } currentOffset = constantOffsets . get ( deviceId ) . getAndAdd ( bytes ) ; if ( currentOffset >= MAX_CONSTANT_LENGTH ) { if ( point . getAllocationStatus ( ) == AllocationStatus . HOST && CudaEnvironment . getInstance ( ) . getConfiguration ( ) . getMemoryModel ( ) == Configuration . MemoryModel . DELAYED ) { AtomicAllocator . getInstance ( ) . getMemoryHandler ( ) . alloc ( AllocationStatus . DEVICE , point , point . getShape ( ) , false ) ; } val profD = PerformanceTracker . getInstance ( ) . helperStartTransaction ( ) ; if ( NativeOpsHolder . getInstance ( ) . getDeviceNativeOps ( ) . memcpyAsync ( point . getPointers ( ) . getDevicePointer ( ) , point . getPointers ( ) . getHostPointer ( ) , requiredMemoryBytes , 1 , context . getSpecialStream ( ) ) == 0 ) { throw new ND4JIllegalStateException ( "memcpyAsync failed" ) ; } flowController . commitTransfer ( context . getSpecialStream ( ) ) ; PerformanceTracker . getInstance ( ) . helperRegisterTransaction ( point . getDeviceId ( ) , profD , point . getNumberOfBytes ( ) , MemcpyDirection . HOST_TO_DEVICE ) ; point . setConstant ( true ) ; point . tickDeviceWrite ( ) ; point . tickHostRead ( ) ; point . setDeviceId ( deviceId ) ; protector . persistDataBuffer ( dataBuffer ) ; return 0 ; } NativeOpsHolder . getInstance ( ) . getDeviceNativeOps ( ) . memcpyConstantAsync ( currentOffset , point . getPointers ( ) . getHostPointer ( ) , requiredMemoryBytes , 1 , context . getSpecialStream ( ) ) ; flowController . commitTransfer ( context . getSpecialStream ( ) ) ; long cAddr = deviceAddresses . get ( deviceId ) . address ( ) + currentOffset ; //if (resetHappened) //    logger.info("copying to constant: {}, bufferLength: {}, bufferDtype: {}, currentOffset: {}, currentAddres: {}", requiredMemoryBytes, dataBuffer.length(), dataBuffer.dataType(), currentOffset, cAddr); point . setAllocationStatus ( AllocationStatus . CONSTANT ) ; point . getPointers ( ) . setDevicePointer ( new CudaPointer ( cAddr ) ) ; point . setConstant ( true ) ; point . tickDeviceWrite ( ) ; point . setDeviceId ( deviceId ) ; point . tickHostRead ( ) ; protector . persistDataBuffer ( dataBuffer ) ; return cAddr ; }
This method moves specified dataBuffer to CUDA constant memory space.

PLEASE NOTE: CUDA constant memory is limited to 48KB per device.

@param dataBuffer
@return
This method moves specified dataBuffer to CUDA constant memory space .