| 143 | |
| 144 | template <bool dynamic, typename dtype> |
| 145 | void test_aplusb() { |
| 146 | using Gen = HostTensorGenerator<dtype>; |
| 147 | using ctype = typename Gen::ctype; |
| 148 | Gen gen; |
| 149 | constexpr size_t SIZE = 1234; |
| 150 | auto host_x = gen({SIZE}), host_y = gen({SIZE}); |
| 151 | auto graph = ComputingGraph::make(); |
| 152 | SymbolVar x = opr::Host2DeviceCopy::make(*graph, host_x).rename("x"), |
| 153 | y = opr::Host2DeviceCopy::make(*graph, host_y).rename("y"); |
| 154 | if (dynamic) { |
| 155 | x = opr::MarkDynamicVar::make(x).rename("xd"); |
| 156 | y = opr::MarkDynamicVar::make(y).rename("yd"); |
| 157 | } |
| 158 | auto z = opr::add(x, y).rename("z"); |
| 159 | HostTensorND host_z; |
| 160 | auto func = graph->compile({make_callback_copy(z, host_z)}); |
| 161 | |
| 162 | for (ctype delta = 0; delta < 2; ++delta) { |
| 163 | auto px = host_x->template ptr<ctype>(); |
| 164 | px[0] += delta; // test change input data |
| 165 | func->execute(); |
| 166 | auto py = host_y->template ptr<ctype>(), pz = host_z.template ptr<ctype>(); |
| 167 | ASSERT_EQ(host_x->shape(), host_z.shape()); |
| 168 | for (size_t i = 0; i < SIZE; ++i) { |
| 169 | MGB_ASSERT_FLOAT_EQ(px[i] + py[i], pz[i]) |
| 170 | << ssprintf("failed at %zu: %g+%g", i, float(px[i]), float(py[i])); |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | class TrackableStaticMemAlloc final : public cg::DeviceMemoryAllocator { |
| 176 | SmallVector<DeviceTensorStorage> m_refhold; |