static*/
| 444 | } |
| 445 | |
| 446 | /*static*/ Status XRTTupleAllocation::MakeTuple( |
| 447 | XRTMemoryManager* memory_manager, xla::Backend* backend, int device_ordinal, |
| 448 | const xla::ShapeTree<ExpandedTupleInput>& elements, |
| 449 | XRTTupleAllocation** allocation) { |
| 450 | auto transfer_manager = backend->transfer_manager(); |
| 451 | auto allocator = backend->memory_allocator(); |
| 452 | TF_ASSIGN_OR_RETURN(auto stream, backend->BorrowStream(device_ordinal)); |
| 453 | |
| 454 | xla::Shape host_shape; |
| 455 | xla::Shape device_shape; |
| 456 | TF_RETURN_IF_ERROR(ExpandTreeOfTuples(elements, device_ordinal, allocator, |
| 457 | &host_shape, &device_shape)); |
| 458 | |
| 459 | // The aliasing is determined below based on whether or not all the inputs are |
| 460 | // released while being transferred. allocation_tmp is a local pointer that is |
| 461 | // copied to *allocation at the end only if the method succeeds. |
| 462 | XRTTupleAllocation* allocation_tmp = new XRTTupleAllocation( |
| 463 | device_ordinal, allocator, host_shape, device_shape); |
| 464 | core::ScopedUnref allocation_unref(allocation_tmp); |
| 465 | // First allocate device memory for the new tuple index tables, one at each |
| 466 | // internal node of the elements tree. Do this in a separate pass into a |
| 467 | // ScopedShapedBuffer so that it's easy to free the newly-allocated memory if |
| 468 | // an allocation fails. Make sure the shape has layout so that the code that |
| 469 | // writes index tables will be happy lower down. |
| 470 | xla::Shape spine_shape = elements.shape(); |
| 471 | xla::LayoutUtil::SetToDefaultLayout(&spine_shape); |
| 472 | auto new_tuple_buffers = absl::make_unique<xla::ScopedShapedBuffer>( |
| 473 | spine_shape, spine_shape, allocator, device_ordinal); |
| 474 | TF_RETURN_IF_ERROR(elements.ForEachElementWithStatus( |
| 475 | [&](const xla::ShapeIndex& index, const ExpandedTupleInput& element) { |
| 476 | if (!elements.IsLeaf(index)) { |
| 477 | const xla::Shape& subshape = |
| 478 | xla::ShapeUtil::GetSubshape(device_shape, index); |
| 479 | uint64 size = transfer_manager->GetByteSizeRequirement(subshape); |
| 480 | TF_ASSIGN_OR_RETURN( |
| 481 | se::OwningDeviceMemory buffer, |
| 482 | memory_manager->Allocate(backend, device_ordinal, size)); |
| 483 | VLOG(2) << "Allocated buffer at " << buffer->opaque() << " index " |
| 484 | << index.ToString(); |
| 485 | // Move the new buffer into new_tuple_buffers, which takes ownership |
| 486 | // of it. |
| 487 | new_tuple_buffers->set_buffer(std::move(buffer), index); |
| 488 | } |
| 489 | return Status::OK(); |
| 490 | })); |
| 491 | // Transfer from the ScopedShapedBuffer to a ShapedBuffer, which does not own |
| 492 | // the newly-allocated index tables. Right now there's no owner for the new |
| 493 | // index tables, so next we will transfer ownership to the new allocation, |
| 494 | // taking care not to return early on any errors in the meantime. |
| 495 | xla::ShapedBuffer tuple_buffers = new_tuple_buffers->release(); |
| 496 | // Now fill in the remaining datastructures. After this ForEachElement |
| 497 | // completes: |
| 498 | // 1) Every leaf element of tuple_buffers will be the root buffer of |
| 499 | // an existing allocation, and every internal element of tuple_buffers |
| 500 | // will be a newly-allocated index table. tuple_buffers does not own any |
| 501 | // of these. |
| 502 | // 2) Every element of allocation_tmp->buffers_ will be a correctly |
| 503 | // constructed |
nothing calls this directly
no test coverage detected