| 28 | namespace opencl { |
| 29 | template<typename T> |
| 30 | Array<T> join(const int jdim, const Array<T> &first, const Array<T> &second) { |
| 31 | // All dimensions except join dimension must be equal |
| 32 | const dim4 &fdims{first.dims()}; |
| 33 | const dim4 &sdims{second.dims()}; |
| 34 | // Compute output dims |
| 35 | dim4 odims(fdims); |
| 36 | odims.dims[jdim] += sdims.dims[jdim]; |
| 37 | Array<T> out = createEmptyArray<T>(odims); |
| 38 | |
| 39 | // topspeed is achieved when byte size(in+out) ~= L2CacheSize |
| 40 | // |
| 41 | // 1 array: memcpy always copies 1 array. topspeed |
| 42 | // --> size(in) <= L2CacheSize/2 |
| 43 | // 2 arrays: topspeeds |
| 44 | // - size(in) < L2CacheSize/2/2 |
| 45 | // --> JIT can copy 2 arrays in // and is fastest |
| 46 | // (condition: array sizes have to be identical) |
| 47 | // - size(in) < L2CacheSize/2 |
| 48 | // --> memcpy will achieve highest speed, although the kernel |
| 49 | // has to be called twice |
| 50 | // - size(in) >= L2CacheSize/2 |
| 51 | // --> memcpy will achieve veryLargeArray speed. The kernel |
| 52 | // will be called twice |
| 53 | if (fdims.dims[jdim] == sdims.dims[jdim]) { |
| 54 | const size_t L2CacheSize{getL2CacheSize(opencl::getDevice())}; |
| 55 | if (!(first.isReady() || second.isReady()) || |
| 56 | (fdims.elements() * sizeof(T) * 2 * 2 < L2CacheSize)) { |
| 57 | // Both arrays have same size & everything fits into the cache, |
| 58 | // so thread in 1 JIT kernel, iso individual copies which is |
| 59 | // always slower |
| 60 | const dim_t *outStrides{out.strides().dims}; |
| 61 | vector<Param> outputs{ |
| 62 | {out.get(), |
| 63 | {{fdims.dims[0], fdims.dims[1], fdims.dims[2], fdims.dims[3]}, |
| 64 | {outStrides[0], outStrides[1], outStrides[2], outStrides[3]}, |
| 65 | 0}}, |
| 66 | {out.get(), |
| 67 | {{sdims.dims[0], sdims.dims[1], sdims.dims[2], sdims.dims[3]}, |
| 68 | {outStrides[0], outStrides[1], outStrides[2], outStrides[3]}, |
| 69 | fdims.dims[jdim] * outStrides[jdim]}}}; |
| 70 | // Extend the life of the returned node, bij saving the |
| 71 | // corresponding shared_ptr |
| 72 | const Node_ptr fNode{first.getNode()}; |
| 73 | const Node_ptr sNode{second.getNode()}; |
| 74 | vector<Node *> nodes{fNode.get(), sNode.get()}; |
| 75 | evalNodes(outputs, nodes); |
| 76 | return out; |
| 77 | } |
| 78 | // continue because individually processing is faster |
| 79 | } |
| 80 | |
| 81 | // Handle each array individually |
| 82 | if (first.isReady()) { |
| 83 | if (1LL + jdim >= first.ndims() && first.isLinear()) { |
| 84 | // first & out are linear |
| 85 | getQueue().enqueueCopyBuffer( |
| 86 | *first.get(), *out.get(), first.getOffset() * sizeof(T), 0, |
| 87 | first.elements() * sizeof(T), nullptr, nullptr); |
no test coverage detected