docs: @Override protected void execImpl() {
      Frame frame = source;
      if (shuffle) {
        // FIXME: switch to global shuffle
        frame = MRUtils.shuffleFramePerChunk(Utils.generateShuffledKey(frame._key), frame, seed);
        frame.delete_and_lock(null).unlock(null); // save frame to DKV
        // delete frame on the end
        gtrash(frame);
      }
      FrameSplitter fs = new FrameSplitter(frame, ratios);
      H2O.submitTask(fs);
  
      Frame[] splits = fs.getResult();
  
      split_keys = new Key [splits.length];
      split_rows = new long[splits.length];
      float rsum = Utils.sum(ratios);
      split_ratios = Arrays.copyOf(ratios, splits.length);
      split_ratios[splits.length-1] = 1f-rsum;
      long sum = 0;
      for(int i=0; i<splits.length; i++) {
        sum += splits[i].numRows();
        split_keys[i] = splits[i]._key;
        split_rows[i] = splits[i].numRows();
      }
      assert sum == source.numRows() : "Frame split produced wrong number of rows: nrows(source) != sum(nrows(splits))";
    }