| 80 | XRTCompileOp::XRTCompileOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} |
| 81 | |
| 82 | Status XRTCompileOp::Compile(OpKernelContext* ctx, |
| 83 | const xrt::XLAComputation& computation_proto, |
| 84 | std::unique_ptr<xla::LocalExecutable>* program) { |
| 85 | const xrt::XLAComputationConfig& config = computation_proto.config(); |
| 86 | |
| 87 | // The default config value is 0; treat it as 1 for convenience. |
| 88 | int num_replicas = config.num_replicas() ? config.num_replicas() : 1; |
| 89 | TF_RET_CHECK(num_replicas == 1); |
| 90 | int num_cores_per_replica = |
| 91 | config.num_cores_per_replica() ? config.num_cores_per_replica() : 1; |
| 92 | TF_RET_CHECK(num_cores_per_replica == 1); |
| 93 | TF_RET_CHECK(config.per_core_program_shape_size() == 0); |
| 94 | |
| 95 | // We are guaranteed that the underlying device object won't be deleted out |
| 96 | // from under us, while the ScopedRef is live. |
| 97 | class XRTGenericDeviceAccessor::ScopedRef device_ref; |
| 98 | TF_RETURN_IF_ERROR( |
| 99 | XRTGenericDeviceAccessor::InitScopedRef(ctx, 0, &device_ref)); |
| 100 | |
| 101 | xla::LocalClient* client = device_ref.client(); |
| 102 | |
| 103 | // There is officially no way to use XLA in a client/server architecture where |
| 104 | // client and server are built from different revisions, because the XLA team |
| 105 | // does not want to give any guarantees about the stability of the Hlo |
| 106 | // proto. For cloud TPU this is fine because server and client versions can be |
| 107 | // assumed to be synced to the same version. For general use the mechanism |
| 108 | // here (using a snapshot from XlaComputation) works as well as the "official" |
| 109 | // XLA client/server design, which serializes the same proto between client |
| 110 | // and server, so in reality is probably fine. |
| 111 | TF_ASSIGN_OR_RETURN(xla::XlaComputation computation, |
| 112 | client->LoadSnapshot(computation_proto.hlo_snapshot())); |
| 113 | |
| 114 | std::vector<xla::Shape> argument_layouts( |
| 115 | config.program_shape().parameters_size()); |
| 116 | std::vector<const xla::Shape*> argument_layout_ptrs( |
| 117 | config.program_shape().parameters_size()); |
| 118 | for (int i = 0; i < config.program_shape().parameters_size(); ++i) { |
| 119 | argument_layouts[i] = xla::Shape(config.program_shape().parameters(i)); |
| 120 | argument_layout_ptrs[i] = &argument_layouts[i]; |
| 121 | } |
| 122 | xla::ExecutableBuildOptions build_options; |
| 123 | build_options.set_device_ordinal(client->default_device_ordinal()); |
| 124 | build_options.set_result_layout(xla::Shape(config.program_shape().result())); |
| 125 | build_options.set_device_allocator(device_ref.backend()->memory_allocator()); |
| 126 | if (config.has_debug_options()) { |
| 127 | *build_options.mutable_debug_options() = |
| 128 | BuildXlaDebugOptions(config.debug_options()); |
| 129 | } |
| 130 | |
| 131 | VLOG(1) << "Building executable"; |
| 132 | TF_ASSIGN_OR_RETURN( |
| 133 | auto executables, |
| 134 | client->Compile(computation, argument_layout_ptrs, build_options)); |
| 135 | TF_RET_CHECK(executables.size() == 1); |
| 136 | *program = std::move(executables[0]); |
| 137 | return Status::OK(); |
| 138 | } |
| 139 |
nothing calls this directly
no test coverage detected