Skip to content

Commit 8bbcb52

Browse files
basioli-ktensorflower-gardener
authored andcommitted
[XLA:CPU][tfcompile] Implement various things needed for future AOT use
- sort thunk - copy thunk - rename use vars PiperOrigin-RevId: 764317163
1 parent a4e019d commit 8bbcb52

3 files changed

Lines changed: 157 additions & 56 deletions

File tree

tensorflow/compiler/aot/BUILD

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,15 @@ cc_library(
4545
"@com_google_absl//absl/status",
4646
"@com_google_absl//absl/status:statusor",
4747
"@com_google_absl//absl/strings",
48-
"@local_xla//xla:cpu_function_runtime",
4948
"@local_xla//xla:shape_util",
49+
"@local_xla//xla:status_macros",
5050
"@local_xla//xla:util",
5151
"@local_xla//xla:xla_data_proto_cc",
5252
"@local_xla//xla/backends/cpu/runtime:convolution_lib",
5353
"@local_xla//xla/backends/cpu/runtime:dot_lib",
5454
"@local_xla//xla/backends/cpu/runtime:thunk_proto_cc",
55-
"@local_xla//xla/service/cpu:cpu_aot_compilation_result",
56-
"@local_xla//xla/service/cpu:cpu_executable",
5755
"@local_xla//xla/service/cpu:executable_proto_cc",
56+
"@local_xla//xla/tsl/platform:statusor",
5857
],
5958
)
6059

tensorflow/compiler/aot/thunk_proto_execution_deserializer.cc

Lines changed: 152 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ limitations under the License.
3030
#include "xla/backends/cpu/runtime/convolution_lib.h"
3131
#include "xla/backends/cpu/runtime/dot_lib.h"
3232
#include "xla/backends/cpu/runtime/thunk.pb.h"
33+
#include "xla/layout_util.h"
3334
#include "xla/service/cpu/executable.pb.h"
3435
#include "xla/shape.h"
3536
#include "xla/shape_util.h"
37+
#include "xla/status_macros.h"
38+
#include "xla/tsl/platform/statusor.h"
3639
#include "xla/util.h"
3740
#include "xla/xla_data.pb.h"
3841

@@ -43,7 +46,7 @@ namespace {
4346

4447
std::string GetBufferAllocationString(
4548
const xla::buffer_assignment::BufferAllocationSliceProto& slice) {
46-
return absl::StrCat("reinterpret_cast<std::byte*>(buffer_table()[",
49+
return absl::StrCat("reinterpret_cast<std::byte*>(buffer_table[",
4750
slice.buffer_allocation_index(), "]) + ", slice.offset());
4851
}
4952

@@ -73,11 +76,6 @@ ThunkProtoExecutionDeserializer::ThunkSpecificRunImplFromThunkSequence(
7376
GetDotThunkRunImpl(thunk));
7477
break;
7578
}
76-
case xla::cpu::ThunkProto::kCopyThunk: {
77-
TF_ASSIGN_OR_RETURN(thunk_run_impls.emplace_back(),
78-
GetCopyThunkRunImpl(thunk));
79-
break;
80-
}
8179
case xla::cpu::ThunkProto::kConditionalThunk: {
8280
TF_ASSIGN_OR_RETURN(thunk_run_impls.emplace_back(),
8381
GetConditionalThunkRunImpl(thunk));
@@ -103,6 +101,16 @@ ThunkProtoExecutionDeserializer::ThunkSpecificRunImplFromThunkSequence(
103101
GetCallThunkRunImpl(thunk));
104102
break;
105103
}
104+
case xla::cpu::ThunkProto::kCopyThunk: {
105+
TF_ASSIGN_OR_RETURN(thunk_run_impls.emplace_back(),
106+
GetCopyThunkRunImpl(thunk));
107+
break;
108+
}
109+
case xla::cpu::ThunkProto::kSortThunk: {
110+
TF_ASSIGN_OR_RETURN(thunk_run_impls.emplace_back(),
111+
GetSortThunkRunImpl(thunk));
112+
break;
113+
}
106114
default: {
107115
return xla::Internal("Unsupported thunk type: %s.", thunk.kind());
108116
}
@@ -151,9 +159,9 @@ absl::StatusOr<std::string> ThunkProtoExecutionDeserializer::GetDotThunkRunImpl(
151159
absl::string_view dot_thunk_invocation_format = R"(
152160
// Dot Thunk
153161
{
154-
if (run_options()->intra_op_thread_pool() != nullptr) {
162+
if (run_options->intra_op_thread_pool() != nullptr) {
155163
{{MATMUL_FUNCTION}}(
156-
run_options(), {{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}},
164+
run_options, {{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}},
157165
{{M}}, {{N}}, {{K}}, {{TRANSPOSE_LHS}}, {{TRANSPOSE_RHS}});
158166
} else {
159167
{{SINGLE_THREADED_MATMUL_FUNCTION}}(
@@ -302,9 +310,9 @@ ThunkProtoExecutionDeserializer::GetConvolution2DRunImpl(
302310
absl::string_view convolution_thunk_invocation_format = R"(
303311
// Convolution Thunk
304312
{
305-
if (run_options()->intra_op_thread_pool() != nullptr) {
313+
if (run_options->intra_op_thread_pool() != nullptr) {
306314
{{CONVOLUTION_FUNCTION}}(
307-
run_options(),
315+
run_options,
308316
{{OUTPUT_PTR}}, {{LHS_PTR}}, {{RHS_PTR}}, {{INPUT_BATCH}},
309317
{{INPUT_ROWS}}, {{INPUT_COLS}}, {{INPUT_CHANNELS}}, {{KERNEL_ROWS}},
310318
{{KERNEL_COLS}}, {{KERNEL_CHANNELS}}, {{KERNEL_FILTERS}},
@@ -417,7 +425,7 @@ ThunkProtoExecutionDeserializer::GetRngGetAndUpdateStateThunkRunImpl(
417425
absl::string_view rng_thunk_invocation_format = R"(
418426
// Rng Thunk
419427
{
420-
rng_states_[{{RNG_STATE_INDEX}}].GetAndUpdateState({{RNG_STATE_PTR}});
428+
rng_states[{{RNG_STATE_INDEX}}]->GetAndUpdateState({{RNG_STATE_PTR}});
421429
})";
422430

423431
if (rng_thunk.state_buffer().size() != sizeof(absl::int128)) {
@@ -458,6 +466,137 @@ ThunkProtoExecutionDeserializer::GetCallThunkRunImpl(
458466
{{"{{CALL_THUNK_IMPL}}", call_thunk_impl}});
459467
}
460468

469+
absl::StatusOr<std::string>
470+
ThunkProtoExecutionDeserializer::GetCopyThunkRunImpl(
471+
const xla::cpu::ThunkProto& thunk) {
472+
// IMPORTANT(basioli): tfcompiled models should always emit llvm kernels for
473+
// copy thunks. Here we emit just a memcpy. This is done exclusively for copy
474+
// thunks that get created by the sort thunk.
475+
if (!thunk.has_copy_thunk()) {
476+
return xla::Internal(
477+
"Copy thunk was expected when getting thunk run implementation.");
478+
}
479+
480+
const xla::cpu::CopyThunkProto& copy_thunk = thunk.copy_thunk();
481+
TF_ASSIGN_OR_RETURN(
482+
auto input_shape,
483+
xla::Shape::FromProto(copy_thunk.src_buffer_shape().shape()));
484+
TF_ASSIGN_OR_RETURN(
485+
auto output_shape,
486+
xla::Shape::FromProto(copy_thunk.dst_buffer_shape().shape()));
487+
488+
if (input_shape != output_shape) {
489+
return xla::Internal(
490+
"Copy thunk has input shape %s and output shape %s that are not the "
491+
"same.",
492+
input_shape.ToString(true), output_shape.ToString(true));
493+
}
494+
495+
absl::string_view copy_thunk_invocation_format = R"(
496+
// Copy Thunk
497+
{
498+
std::memcpy({{OUTPUT_PTR}}, {{INPUT_PTR}}, {{SIZE}});
499+
})";
500+
501+
return absl::StrReplaceAll(
502+
copy_thunk_invocation_format,
503+
{{"{{OUTPUT_PTR}}",
504+
absl::StrCat(
505+
"reinterpret_cast<char*>(",
506+
GetBufferAllocationString(copy_thunk.dst_buffer_shape().slice()),
507+
")")},
508+
{"{{INPUT_PTR}}",
509+
absl::StrCat(
510+
"reinterpret_cast<char*>(",
511+
GetBufferAllocationString(copy_thunk.src_buffer_shape().slice()),
512+
")")},
513+
{"{{SIZE}}",
514+
absl::StrCat(copy_thunk.src_buffer_shape().slice().size())}});
515+
}
516+
517+
absl::StatusOr<std::string>
518+
ThunkProtoExecutionDeserializer::GetSortThunkRunImpl(
519+
const xla::cpu::ThunkProto& thunk) {
520+
if (!thunk.has_sort_thunk()) {
521+
return xla::Internal(
522+
"Sort thunk was expected when getting thunk run implementation.");
523+
}
524+
const xla::cpu::SortThunkProto& sort_thunk = thunk.sort_thunk();
525+
526+
std::vector<std::string> buffers_to_sort;
527+
buffers_to_sort.reserve(sort_thunk.inputs_shapes_size());
528+
529+
std::vector<int32_t> values_primitive_type_size_in_bytes;
530+
values_primitive_type_size_in_bytes.reserve(sort_thunk.inputs_shapes_size());
531+
for (const auto& buffer_proto : sort_thunk.inputs_shapes()) {
532+
buffers_to_sort.push_back(
533+
absl::StrCat("reinterpret_cast<char*>(",
534+
GetBufferAllocationString(buffer_proto.slice()), ")"));
535+
values_primitive_type_size_in_bytes.push_back(
536+
xla::ShapeUtil::ByteSizeOfPrimitiveType(
537+
buffer_proto.shape().element_type()));
538+
}
539+
absl::string_view sort_thunk_invocation_format = R"(
540+
// Sort Thunk
541+
{
542+
std::vector<char*> values = {
543+
{{BUFFERS_TO_SORT}}
544+
};
545+
std::vector<int32_t> values_primitive_type_size_in_bytes = {
546+
{{VALUES_PRIMITIVE_TYPE_SIZE_IN_BYTES}}
547+
};
548+
549+
__xla_cpu_runtime_KeyValueSort(
550+
{{HIGHER_DIMENSIONS}}, {{SORT_DIMENSION_ELEMENTS}}, {{LOWER_DIMENSIONS}},
551+
values.data(),
552+
int32_t(values.size()),
553+
values_primitive_type_size_in_bytes.data(),
554+
/*is_stable=*/{{IS_STABLE}},
555+
reinterpret_cast<char*>(run_options),
556+
/*prof_counters=*/nullptr,
557+
reinterpret_cast<void(*)(char*, char*, char**, char**, int64_t*)>({{SORT_FUNCTION_NAME}}));
558+
})";
559+
560+
TF_ASSIGN_OR_RETURN(
561+
auto keys_shape,
562+
xla::Shape::FromProto(sort_thunk.inputs_shapes(0).shape()));
563+
564+
// Normalize the shape and the dimension to sort.
565+
xla::Shape normalized_keys_shape =
566+
xla::ShapeUtil::MakeShapeWithDescendingLayoutAndSamePhysicalLayout(
567+
keys_shape);
568+
auto logical_to_physical =
569+
xla::LayoutUtil::MakeLogicalToPhysical(keys_shape.layout());
570+
TF_RET_CHECK(sort_thunk.dimension() < logical_to_physical.size());
571+
int64_t physical_dimension_to_sort =
572+
logical_to_physical[sort_thunk.dimension()];
573+
574+
int64_t sort_dimension_elements =
575+
normalized_keys_shape.dimensions(physical_dimension_to_sort);
576+
int64_t higher_dimensions = 1;
577+
for (int64_t i = 0; i < physical_dimension_to_sort; ++i) {
578+
higher_dimensions *= normalized_keys_shape.dimensions(i);
579+
}
580+
int64_t lower_dimensions = 1;
581+
for (int64_t i = normalized_keys_shape.dimensions().size() - 1;
582+
i > physical_dimension_to_sort; --i) {
583+
lower_dimensions *= normalized_keys_shape.dimensions(i);
584+
}
585+
return absl::StrReplaceAll(
586+
sort_thunk_invocation_format,
587+
{
588+
{"{{HIGHER_DIMENSIONS}}", absl::StrCat(higher_dimensions)},
589+
{"{{SORT_DIMENSION_ELEMENTS}}",
590+
absl::StrCat(sort_dimension_elements)},
591+
{"{{LOWER_DIMENSIONS}}", absl::StrCat(lower_dimensions)},
592+
{"{{SORT_FUNCTION_NAME}}", sort_thunk.comparator_name()},
593+
{"{{BUFFERS_TO_SORT}}", absl::StrJoin(buffers_to_sort, ", ")},
594+
{"{{VALUES_PRIMITIVE_TYPE_SIZE_IN_BYTES}}",
595+
absl::StrJoin(values_primitive_type_size_in_bytes, ", ")},
596+
{"{{IS_STABLE}}", sort_thunk.is_stable() ? "true" : "false"},
597+
});
598+
}
599+
461600
absl::StatusOr<std::string>
462601
ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
463602
const xla::cpu::ThunkProto& thunk) {
@@ -488,7 +627,7 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
488627
// Kernel Thunk
489628
{
490629
std::array<XLA_CPU_KernelArg, {{NUM_ARGS}}> args = {{ARGS_INITIALIZER}};
491-
XLA_CPU_KernelThreadDim kernel_thread_dims = {
630+
XLA_CPU_NumWorkGroups kernel_thread_dims = {
492631
{{THREAD_DIM_X}},
493632
{{THREAD_DIM_Y}},
494633
{{THREAD_DIM_Z}},
@@ -497,7 +636,7 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
497636
for (uint64_t z = 0; z < {{THREAD_DIM_Z}}; ++z) {
498637
for (uint64_t y = 0; y < {{THREAD_DIM_Y}}; ++y) {
499638
for (uint64_t x = 0; x < {{THREAD_DIM_X}}; ++x) {
500-
XLA_CPU_KernelThread kernel_thread = {x, y, z};
639+
XLA_CPU_WorkGroupId kernel_thread = {x, y, z};
501640
502641
XLA_CPU_KernelCallFrame call_frame = {
503642
&kernel_thread_dims, &kernel_thread, args.size(), args.data()};
@@ -528,46 +667,6 @@ ThunkProtoExecutionDeserializer::GetKernelThunkRunImpl(
528667
});
529668
}
530669

531-
absl::StatusOr<std::string>
532-
ThunkProtoExecutionDeserializer::GetCopyThunkRunImpl(
533-
const xla::cpu::ThunkProto& thunk) {
534-
if (!thunk.has_copy_thunk()) {
535-
return xla::Internal(
536-
"Copy thunk was expected when getting thunk run implementation.");
537-
}
538-
const xla::cpu::CopyThunkProto& copy_thunk = thunk.copy_thunk();
539-
540-
TF_ASSIGN_OR_RETURN(
541-
xla::Shape src_buffer_shape,
542-
xla::Shape::FromProto(copy_thunk.src_buffer_shape().shape()));
543-
TF_ASSIGN_OR_RETURN(
544-
xla::Shape dst_buffer_shape,
545-
xla::Shape::FromProto(copy_thunk.dst_buffer_shape().shape()));
546-
if (!xla::ShapeUtil::Equal(src_buffer_shape, dst_buffer_shape)) {
547-
return xla::Internal("Source and destination shapes must be equal.");
548-
}
549-
550-
absl::string_view copy_invocation_format = R"(
551-
// Copy Thunk
552-
{
553-
std::memcpy({{DST_BUFFER}},
554-
{{SRC_BUFFER}},
555-
{{SRC_BUFFER_SIZE}});
556-
}
557-
)";
558-
559-
return absl::StrReplaceAll(
560-
copy_invocation_format,
561-
{
562-
{"{{DST_BUFFER}}",
563-
GetBufferAllocationString(copy_thunk.dst_buffer_shape().slice())},
564-
{"{{SRC_BUFFER}}",
565-
GetBufferAllocationString(copy_thunk.src_buffer_shape().slice())},
566-
{"{{SRC_BUFFER_SIZE}}",
567-
absl::StrCat(copy_thunk.src_buffer_shape().slice().size())},
568-
});
569-
}
570-
571670
absl::StatusOr<std::string>
572671
ThunkProtoExecutionDeserializer::GetConditionalThunkRunImpl(
573672
const xla::cpu::ThunkProto& thunk) {

tensorflow/compiler/aot/thunk_proto_execution_deserializer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class ThunkProtoExecutionDeserializer {
7676
absl::StatusOr<std::string> GetWhileThunkRunImpl(
7777
const xla::cpu::ThunkProto& thunk);
7878

79+
absl::StatusOr<std::string> GetSortThunkRunImpl(
80+
const xla::cpu::ThunkProto& thunk);
81+
7982
absl::StatusOr<std::string> CppDataTypeFromXlaType(
8083
xla::PrimitiveType xla_type);
8184

0 commit comments

Comments
 (0)