docs: @Override
      public INDArray[] exec(CustomOp op) {
  
          Nd4j.getExecutioner().commit();
  
          //
          if (op.numOutputArguments() == 0 && !op.isInplaceCall()) {
              try {
                  val list = this.calculateOutputShape(op);
                  if (list.isEmpty())
                      throw new ND4JIllegalStateException("Op name " + op.opName() + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified");
  
                  for (val shape: list)
                      op.addOutputArgument(Nd4j.create(shape));
  
              } catch (Exception e) {
                  throw new ND4JIllegalStateException("Op name " + op.opName() + " failed to execute. You can't execute non-inplace CustomOp without outputs being specified");
              }
          }
  
          if (op.opName().equalsIgnoreCase("im2col")) {
              val xArr = op.inputArguments()[0];
              val zArr = op.outputArguments()[0];
  
              CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);
  
              if (extraz.get() == null)
                  extraz.set(new PointerPointer(32));
  
              PointerPointer xShapeHost =
                      extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                              context.getOldStream(), // 1
                              AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                              context.getBufferAllocation(), // 3
                              context.getBufferReduction(), // 4
                              context.getBufferScalar(), // 5
                              context.getBufferSpecial(),
                              null,
                              AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                      );
  
  
              val x = AtomicAllocator.getInstance().getPointer(xArr, context);
              val z = AtomicAllocator.getInstance().getPointer(zArr, context);
  
              val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
              val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);
  
              val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
              val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());
  
              double zeroPad = 0.0;
              if(op.tArgs() != null && op.tArgs().length > 0){
                  zeroPad = op.tArgs()[0];
              }
              val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7], op.iArgs()[8], zeroPad};
              val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, xArr.dataType());
              val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);
  
              nativeOps.execTransformSame(xShapeHost, 9,
                      null, (LongPointer) hxShape, x, (LongPointer) xShape,
                      null, (LongPointer) hzShape, z, (LongPointer) zShape, extraArgs);
  
              //AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
              AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);
  
              Nd4j.getExecutioner().commit();
  
              return op.outputArguments();
          } else if (op.opName().equalsIgnoreCase("col2im")) {
              val dtype = Nd4j.dataType();
  
              val xArr = op.inputArguments()[0];
              val zArr = op.outputArguments()[0];
  
              CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);
  
              if (extraz.get() == null)
                  extraz.set(new PointerPointer(32));
  
              PointerPointer xShapeHost =
                      extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                              context.getOldStream(), // 1
                              AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                              context.getBufferAllocation(), // 3
                              context.getBufferReduction(), // 4
                              context.getBufferScalar(), // 5
                              context.getBufferSpecial(),
                              null,
                              AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                      );
  
  
              val x = AtomicAllocator.getInstance().getPointer(xArr, context);
              val z = AtomicAllocator.getInstance().getPointer(zArr, context);
  
              val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
              val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);
  
              val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
              val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());
  
              val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7]};
              val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, xArr.dataType());
              val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);
  
  
              nativeOps.execTransformSame(xShapeHost, 8,
                      null, (LongPointer) hxShape, x, (LongPointer) xShape,
                      null, (LongPointer) hzShape, z, (LongPointer) zShape, extraArgs);
  
              //AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
              AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);
  
              //Nd4j.getExecutioner().commit();
              return op.outputArguments();
          } else if (op.opName().equalsIgnoreCase("pooling2d")) {
              val dtype = Nd4j.dataType();
  
              val xArr = op.inputArguments()[0];
              val zArr = op.outputArguments()[0];
  
              CudaContext context = AtomicAllocator.getInstance().getFlowController().prepareAction(zArr, xArr);
  
              if (extraz.get() == null)
                  extraz.set(new PointerPointer(32));
  
              PointerPointer xShapeHost =
                      extraz.get().put(AddressRetriever.retrieveHostPointer(xArr.shapeInfoDataBuffer()), // 0
                              context.getOldStream(), // 1
                              AtomicAllocator.getInstance().getDeviceIdPointer(), // 2
                              context.getBufferAllocation(), // 3
                              context.getBufferReduction(), // 4
                              context.getBufferScalar(), // 5
                              context.getBufferSpecial(),
                              null,
                              AddressRetriever.retrieveHostPointer(zArr.shapeInfoDataBuffer())
                      );
  
  
              val x = AtomicAllocator.getInstance().getPointer(xArr, context);
              val z = AtomicAllocator.getInstance().getPointer(zArr, context);
  
              val xShape = AtomicAllocator.getInstance().getPointer(xArr.shapeInfoDataBuffer(), context);
              val zShape = AtomicAllocator.getInstance().getPointer(zArr.shapeInfoDataBuffer(), context);
  
              val hxShape = AtomicAllocator.getInstance().getHostPointer(xArr.shapeInfoDataBuffer());
              val hzShape = AtomicAllocator.getInstance().getHostPointer(zArr.shapeInfoDataBuffer());
  
              val extrass = new double[]{op.iArgs()[0], op.iArgs()[1], op.iArgs()[2], op.iArgs()[3], op.iArgs()[4], op.iArgs()[5], op.iArgs()[6], op.iArgs()[7], op.iArgs()[8]};
              val extraArgsBuff = Nd4j.getConstantHandler().getConstantBuffer(extrass, zArr.dataType());
              val extraArgs = AtomicAllocator.getInstance().getPointer(extraArgsBuff, context);
  
  
              nativeOps.execTransformFloat(xShapeHost, 23,
                      null, (LongPointer) hxShape, x, (LongPointer) xShape,
                      zArr.data().addressPointer(), (LongPointer) hzShape, z, (LongPointer) zShape,
                      extraArgs);
  
              // AtomicAllocator.getInstance().getAllocationPoint(zArr).tickDeviceWrite();
              AtomicAllocator.getInstance().getFlowController().registerAction(context, zArr, xArr);
  
              return op.outputArguments();
          }
  
          Nd4j.getExecutioner().commit();
  
          val context = buildContext();
  
          context.markInplace(op.isInplaceCall());
  
          // transferring rng state
          context.setRngStates(Nd4j.getRandom().rootState(), Nd4j.getRandom().nodeState());
  
          //transferring input/output arrays
          context.setInputArrays(op.inputArguments());
          context.setOutputArrays(op.outputArguments());
  
          // transferring static args
          context.setBArguments(op.bArgs());
          context.setIArguments(op.iArgs());
          context.setTArguments(op.tArgs());
  
          val result = exec(op, context);
          val states = context.getRngStates();
  
          // pulling states back
          Nd4j.getRandom().setStates(states.getFirst(), states.getSecond());
  
          return result;
  
          /*
          long st = profilingConfigurableHookIn(op);
  
          CudaContext context =(CudaContext) AtomicAllocator.getInstance().getDeviceContext().getContext();
          //AtomicAllocator.getInstance().getFlowController().prepareActionAllWrite(op.outputArguments());
  
          if (extraz.get() == null)
              extraz.set(new PointerPointer(32));
  
  
          PointerPointer extras = extraz.get().put(
                  new CudaPointer(1),
                  context.getOldStream(),
                  context.getBufferScalar(),
                  context.getBufferReduction());
  
          val outputArgs = op.outputArguments();
          val inputArgs = op.inputArguments();
  
          if (outputArgs.length == 0 && !op.isInplaceCall())
              throw new ND4JIllegalStateException("You can't execute non-inplace CustomOp without outputs being specified");
  
          val lc = op.opName().toLowerCase();
          val hash = op.opHash();
  
  
          val inputShapes = new PointerPointer<>(inputArgs.length * 2);
          val inputBuffers = new PointerPointer<>(inputArgs.length * 2);
  
          int cnt= 0;
          for (val in: inputArgs) {
              val hp = AtomicAllocator.getInstance().getHostPointer(in.shapeInfoDataBuffer());
              inputBuffers.put(cnt,  AtomicAllocator.getInstance().getHostPointer(in));
              inputShapes.put(cnt, hp);
  
  
              val dp = AtomicAllocator.getInstance().getPointer(in.shapeInfoDataBuffer(), context);
  
              inputBuffers.put(cnt + inputArgs.length, AtomicAllocator.getInstance().getPointer(in, context));
              inputShapes.put(cnt+ inputArgs.length, dp);
  
              if (op.isInplaceCall()) {
                  val ap = AtomicAllocator.getInstance().getAllocationPoint(in);
                  if (ap != null)
                      ap.tickHostWrite();
              }
  
              cnt++;
          }
  
  
          val outputShapes = new PointerPointer<>(outputArgs.length * 2);
          val outputBuffers = new PointerPointer<>(outputArgs.length * 2);
  
          cnt= 0;
          for (val out: outputArgs) {
              outputBuffers.put(cnt,  AtomicAllocator.getInstance().getHostPointer(out));
              outputShapes.put(cnt,  AtomicAllocator.getInstance().getHostPointer(out.shapeInfoDataBuffer()));
  
              outputBuffers.put(cnt + outputArgs.length,  AtomicAllocator.getInstance().getPointer(out, context));
              outputShapes.put(cnt + outputArgs.length,  AtomicAllocator.getInstance().getPointer(out.shapeInfoDataBuffer(), context));
  
              val ap = AtomicAllocator.getInstance().getAllocationPoint(out);
  
              if (ap != null)
                  ap.tickHostWrite();
  
              cnt++;
          }
  
          val iArgs = op.iArgs().length > 0 ? new LongPointer(op.iArgs().length) : null;
  
          cnt = 0;
          for (val i: op.iArgs())
              iArgs.put(cnt++, i);
  
  
          val tArgs = op.tArgs().length > 0 ? new DoublePointer(op.tArgs().length) : null;
  
          val bArgs = op.bArgs().length > 0 ? new BooleanPointer(op.numBArguments()) : null;
  
          cnt = 0;
          for (val t: op.tArgs())
              tArgs.put(cnt++, t);
  
          cnt = 0;
          for (val b: op.bArgs())
              bArgs.put(cnt++, b);
  
          try {
              val status = OpStatus.byNumber(nativeOps.execCustomOp(extras, hash, inputBuffers, inputShapes, inputArgs.length, outputBuffers, outputShapes, outputArgs.length, tArgs, op.tArgs().length, iArgs, op.iArgs().length, bArgs, op.numBArguments(), op.isInplaceCall()));
              if (status != OpStatus.ND4J_STATUS_OK)
                  throw new ND4JIllegalStateException("Op execution failed: " + status);
          } catch (Exception e) {
              throw new RuntimeException("Op [" + op.opName() + "] execution failed");
          }
  
          //AtomicAllocator.getInstance().getFlowController().prepareActionAllWrite(op.outputArguments());
  
          profilingConfigurableHookOut(op, st);
          return op.outputArguments();
           */
      }