|
23 | 23 | #include <executorch/extension/llm/sampler/util.h> |
24 | 24 | #include <executorch/extension/module/module.h> |
25 | 25 | #include <executorch/extension/tensor/tensor.h> |
| 26 | +#include <executorch/extension/tensor/tensor_ptr.h> |
26 | 27 | #include <executorch/runtime/backend/interface.h> |
27 | 28 | #include <executorch/runtime/backend/options.h> |
| 29 | +#include <executorch/runtime/core/portable_type/device.h> |
| 30 | +#include <executorch/runtime/platform/assert.h> |
28 | 31 | #include <executorch/runtime/platform/log.h> |
29 | 32 | #include <pytorch/tokenizers/hf_tokenizer.h> |
30 | 33 |
|
@@ -82,6 +85,9 @@ using ::executorch::extension::from_blob; |
82 | 85 | using ::executorch::extension::Module; |
83 | 86 | using ::executorch::runtime::Error; |
84 | 87 | using ::executorch::runtime::EValue; |
| 88 | +#ifdef EXECUTORCH_BUILD_CUDA |
| 89 | +using ::executorch::extension::clone_tensor_ptr_to; |
| 90 | +#endif |
85 | 91 |
|
86 | 92 | using SizesType = executorch::aten::SizesType; |
87 | 93 |
|
@@ -181,6 +187,8 @@ int main(int argc, char** argv) { |
181 | 187 | FLAGS_temperature <= 0.0 ? 1e-6f : static_cast<float>(FLAGS_temperature); |
182 | 188 |
|
183 | 189 | #ifdef EXECUTORCH_BUILD_CUDA |
| 190 | + const auto cuda_device = |
| 191 | + executorch::aten::Device(executorch::aten::DeviceType::CUDA, 0); |
184 | 192 | if (FLAGS_cuda_graph) { |
185 | 193 | executorch::runtime::BackendOptions<2> cuda_opts; |
186 | 194 | cuda_opts.set_option("enable_cuda_graph_for_method", "decode"); |
@@ -217,8 +225,9 @@ int main(int argc, char** argv) { |
217 | 225 | ET_LOG(Error, "Failed to load decode method"); |
218 | 226 | return 1; |
219 | 227 | } |
220 | | - auto temp_tensor = |
221 | | - from_blob(&temp_val, {1}, executorch::aten::ScalarType::Float); |
| 228 | + auto temp_tensor = clone_tensor_ptr_to( |
| 229 | + from_blob(&temp_val, {1}, executorch::aten::ScalarType::Float), |
| 230 | + cuda_device); |
222 | 231 | #else |
223 | 232 | if (FLAGS_cuda_graph) { |
224 | 233 | ET_LOG(Info, "--cuda_graph ignored on non-CUDA build"); |
@@ -304,6 +313,12 @@ int main(int argc, char** argv) { |
304 | 313 | auto pos_tensor = from_blob( |
305 | 314 | pos_data.data(), {S(chunk_len)}, executorch::aten::ScalarType::Long); |
306 | 315 |
|
| 316 | +#ifdef EXECUTORCH_BUILD_CUDA |
| 317 | + // skip_h2d: prefill/decode method inputs must already live in CUDA memory. |
| 318 | + tokens_tensor = clone_tensor_ptr_to(tokens_tensor, cuda_device); |
| 319 | + pos_tensor = clone_tensor_ptr_to(pos_tensor, cuda_device); |
| 320 | +#endif |
| 321 | + |
307 | 322 | std::vector<EValue> inputs; |
308 | 323 | inputs.push_back(EValue(tokens_tensor)); |
309 | 324 | inputs.push_back(EValue(pos_tensor)); |
@@ -356,17 +371,49 @@ int main(int argc, char** argv) { |
356 | 371 | int64_t pos = num_prompt_tokens; |
357 | 372 | std::vector<int64_t> decode_token_data = {static_cast<int64_t>(cur_token)}; |
358 | 373 | std::vector<int64_t> decode_pos_data = {pos}; |
359 | | - auto decode_tokens = from_blob( |
| 374 | + auto decode_tokens_cpu = from_blob( |
360 | 375 | decode_token_data.data(), {1, 1}, executorch::aten::ScalarType::Long); |
361 | | - auto decode_pos = from_blob( |
| 376 | + auto decode_pos_cpu = from_blob( |
362 | 377 | decode_pos_data.data(), {1}, executorch::aten::ScalarType::Long); |
| 378 | +#ifdef EXECUTORCH_BUILD_CUDA |
| 379 | + // skip_h2d: keep fixed device-resident input buffers across decode steps |
| 380 | + // (seeded here with a one-time H2D). Their 8-byte contents are refreshed |
| 381 | + // each step from the host (see loop), since the sampled id round-trips to |
| 382 | + // the host for EOS detection. |
| 383 | + auto decode_tokens = clone_tensor_ptr_to(decode_tokens_cpu, cuda_device); |
| 384 | + auto decode_pos = clone_tensor_ptr_to(decode_pos_cpu, cuda_device); |
| 385 | +#else |
| 386 | + auto decode_tokens = decode_tokens_cpu; |
| 387 | + auto decode_pos = decode_pos_cpu; |
| 388 | +#endif |
363 | 389 |
|
364 | 390 | uint64_t prev_token = cur_token; |
365 | 391 | bool hit_eos = eos_ids.find(cur_token) != eos_ids.end(); |
366 | 392 | for (int32_t step = 0; step < FLAGS_max_new_tokens && !hit_eos; step++) { |
367 | 393 | decode_token_data[0] = static_cast<int64_t>(cur_token); |
368 | 394 | decode_pos_data[0] = pos; |
369 | 395 |
|
| 396 | +#ifdef EXECUTORCH_BUILD_CUDA |
| 397 | + // skip_h2d: refresh the device-resident token/pos buffers ourselves (the |
| 398 | + // backend no longer inserts the H2D copy). The prior step's sampled id |
| 399 | + // already came back to the host via read_token, so re-upload the 8-byte |
| 400 | + // token and position into the fixed device buffers. |
| 401 | + ET_CHECK_MSG( |
| 402 | + cudaMemcpy( |
| 403 | + decode_tokens->mutable_data_ptr(), |
| 404 | + decode_token_data.data(), |
| 405 | + sizeof(int64_t), |
| 406 | + cudaMemcpyHostToDevice) == cudaSuccess, |
| 407 | + "Failed to upload decode token H2D"); |
| 408 | + ET_CHECK_MSG( |
| 409 | + cudaMemcpy( |
| 410 | + decode_pos->mutable_data_ptr(), |
| 411 | + decode_pos_data.data(), |
| 412 | + sizeof(int64_t), |
| 413 | + cudaMemcpyHostToDevice) == cudaSuccess, |
| 414 | + "Failed to upload decode position H2D"); |
| 415 | +#endif |
| 416 | + |
370 | 417 | std::vector<EValue> inputs; |
371 | 418 | inputs.push_back(EValue(decode_tokens)); |
372 | 419 | inputs.push_back(EValue(decode_pos)); |
|
0 commit comments