static */
| 548 | } |
| 549 | |
| 550 | /* static */ port::Status GpuDriver::LoadPtx(GpuContext* context, |
| 551 | const char* ptx_contents, |
| 552 | CUmodule* module) { |
| 553 | absl::Notification notification; |
| 554 | port::Status ret = port::Status::OK(); |
| 555 | GetDriverExecutor()->Schedule([context, ptx_contents, module, &ret, |
| 556 | ¬ification]() { |
| 557 | ScopedActivateContext activation(context); |
| 558 | void* ptx_data = const_cast<char*>(ptx_contents); |
| 559 | static const unsigned int kLogBufferBytesLimit = 1024; |
| 560 | unsigned int error_log_buffer_bytes = kLogBufferBytesLimit; |
| 561 | unsigned int info_log_buffer_bytes = kLogBufferBytesLimit; |
| 562 | absl::InlinedVector<char, 4> error_log_buffer(error_log_buffer_bytes); |
| 563 | absl::InlinedVector<char, 4> info_log_buffer(info_log_buffer_bytes); |
| 564 | bool log_verbose = true; |
| 565 | CUjit_option options[] = {CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES, |
| 566 | CU_JIT_ERROR_LOG_BUFFER, |
| 567 | CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES, |
| 568 | CU_JIT_INFO_LOG_BUFFER, CU_JIT_LOG_VERBOSE}; |
| 569 | // Note that the driver API wants the contents of this values to be stored |
| 570 | // in an array of void*s, so we coerce them accordingly. |
| 571 | void* option_values[] = { |
| 572 | absl::bit_cast<void*>(uintptr_t(error_log_buffer_bytes)), |
| 573 | absl::bit_cast<void*>(error_log_buffer.data()), |
| 574 | absl::bit_cast<void*>(uintptr_t(info_log_buffer_bytes)), |
| 575 | absl::bit_cast<void*>(info_log_buffer.data()), |
| 576 | absl::bit_cast<void*>(uintptr_t(log_verbose))}; |
| 577 | CHECK(TF_ARRAYSIZE(options) == TF_ARRAYSIZE(option_values)); |
| 578 | |
| 579 | CUresult res; |
| 580 | { |
| 581 | // TODO(leary) Need to see if NVIDIA can expunge the leakiness in their |
| 582 | // module loading: see http://b/13248943 |
| 583 | absl::LeakCheckDisabler disabler; |
| 584 | res = cuModuleLoadDataEx(module, ptx_data, TF_ARRAYSIZE(options), options, |
| 585 | option_values); |
| 586 | } |
| 587 | |
| 588 | // The PTX JIT mutates the values in the option values array to reflect the |
| 589 | // size of the logs it output; now that we've made the call, read the values |
| 590 | // back out. |
| 591 | error_log_buffer_bytes = reinterpret_cast<uintptr_t>(option_values[0]); |
| 592 | info_log_buffer_bytes = reinterpret_cast<uintptr_t>(option_values[2]); |
| 593 | CHECK_LE(error_log_buffer_bytes, kLogBufferBytesLimit); |
| 594 | CHECK_LE(info_log_buffer_bytes, kLogBufferBytesLimit); |
| 595 | |
| 596 | if (res != CUDA_SUCCESS) { |
| 597 | LOG(ERROR) << "failed to load PTX text as a module: " << ToString(res); |
| 598 | // As a precaution for null termination of the API-provided value, ensure |
| 599 | // that at least the last byte is null. |
| 600 | error_log_buffer[error_log_buffer_bytes ? error_log_buffer_bytes - 1 |
| 601 | : 0] = '\0'; |
| 602 | LOG(ERROR) << "error log buffer (" << error_log_buffer_bytes |
| 603 | << " bytes): " << error_log_buffer.data(); |
| 604 | ret = port::InternalError( |
| 605 | absl::StrCat("Failed to load PTX text as a module: ", ToString(res))); |
| 606 | notification.Notify(); |
| 607 | } |
nothing calls this directly
no test coverage detected