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