aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Sanjoy Das <sanjoy@google.com>2017-11-30 11:23:25 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-11-30 11:27:07 -0800
commiteafa8efc55fb9989a679e36b030742c6d87b0310 (patch)
tree16fbaafc1c3b92a2c541f7e8ddede80c4c310944
parent4146ff1259c0b4ada8afbbad11a7b37d8373d1b9 (diff)
[XLA:CPU] Add Hlo profiling support to XlaJitCompiledCpuFunction
Some of the functionality has bled into the generic XlaCompiledCpuFunction, but there still remains a fair amount of work to do before the AOT side of things start working. This CL also fixes a bug I introduced in a previous CL -- when I changed IrEmitter::hlo_to_profile_idx_ to a value, I changed the signature of the generated function to always have the "profile_counters" argument when the AOT client code expects the signature to not have that argument. In practice this wasn't an issue for the standard x86 calling convention, but it could easily have been problematic on other architectures and calling conventions. After this change the mismatch is no longer present. PiperOrigin-RevId: 177481998
-rw-r--r--tensorflow/compiler/aot/codegen.cc8
-rw-r--r--tensorflow/compiler/aot/codegen_test_h.golden8
-rw-r--r--tensorflow/compiler/aot/tests/tfcompile_test.cc4
-rw-r--r--tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc15
-rw-r--r--tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h53
-rw-r--r--tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc25
-rw-r--r--tensorflow/compiler/xla/service/cpu/ir_function.cc2
-rw-r--r--tensorflow/compiler/xla/service/hlo_execution_profile.cc3
-rw-r--r--tensorflow/compiler/xla/service/hlo_profile_printer.h8
9 files changed, 82 insertions, 44 deletions
diff --git a/tensorflow/compiler/aot/codegen.cc b/tensorflow/compiler/aot/codegen.cc
index ae22f7edc4..28ac40df18 100644
--- a/tensorflow/compiler/aot/codegen.cc
+++ b/tensorflow/compiler/aot/codegen.cc
@@ -418,7 +418,7 @@ namespace xla { class ExecutableRunOptions; }
// (Implementation detail) Entry point to the function in the object file.
extern "C" void {{ENTRY}}(
void* result, const xla::ExecutableRunOptions* run_options,
- const void** args, void** temps);
+ const void** args, void** temps, tensorflow::int64* profile_counters);
{{NS_START}}
// {{CLASS}} represents a computation previously specified in a
@@ -483,7 +483,7 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction {
return *kStaticData;
}
- {{CLASS}}(AllocMode alloc_mode = AllocMode::ARGS_RESULTS_AND_TEMPS)
+ {{CLASS}}(AllocMode alloc_mode = AllocMode::ARGS_RESULTS_PROFILES_AND_TEMPS)
: XlaCompiledCpuFunction(StaticData(), alloc_mode) {}
{{CLASS}}(const {{CLASS}}&) = delete;
@@ -496,8 +496,8 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction {
// void set_argN_data(void* data)
// Sets the buffer of type T for positional argument N. May be called in
// any AllocMode. Must be called before Run to have an affect. Must be
- // called in AllocMode::RESULTS_AND_TEMPS_ONLY for each positional argument,
- // to set the argument buffers.
+ // called in AllocMode::RESULTS_PROFILES_AND_TEMPS_ONLY for each positional
+ // argument, to set the argument buffers.
//
// T* argN_data()
// Returns the buffer of type T for positional argument N.
diff --git a/tensorflow/compiler/aot/codegen_test_h.golden b/tensorflow/compiler/aot/codegen_test_h.golden
index 65f342ce27..cf01bee325 100644
--- a/tensorflow/compiler/aot/codegen_test_h.golden
+++ b/tensorflow/compiler/aot/codegen_test_h.golden
@@ -19,7 +19,7 @@ namespace xla { class ExecutableRunOptions; }
// (Implementation detail) Entry point to the function in the object file.
extern "C" void entry_point(
void* result, const xla::ExecutableRunOptions* run_options,
- const void** args, void** temps);
+ const void** args, void** temps, tensorflow::int64* profile_counters);
namespace foo {
namespace bar {
@@ -86,7 +86,7 @@ class MyClass : public tensorflow::XlaCompiledCpuFunction {
return *kStaticData;
}
- MyClass(AllocMode alloc_mode = AllocMode::ARGS_RESULTS_AND_TEMPS)
+ MyClass(AllocMode alloc_mode = AllocMode::ARGS_RESULTS_PROFILES_AND_TEMPS)
: XlaCompiledCpuFunction(StaticData(), alloc_mode) {}
MyClass(const MyClass&) = delete;
@@ -99,8 +99,8 @@ class MyClass : public tensorflow::XlaCompiledCpuFunction {
// void set_argN_data(void* data)
// Sets the buffer of type T for positional argument N. May be called in
// any AllocMode. Must be called before Run to have an affect. Must be
- // called in AllocMode::RESULTS_AND_TEMPS_ONLY for each positional argument,
- // to set the argument buffers.
+ // called in AllocMode::RESULTS_PROFILES_AND_TEMPS_ONLY for each positional
+ // argument, to set the argument buffers.
//
// T* argN_data()
// Returns the buffer of type T for positional argument N.
diff --git a/tensorflow/compiler/aot/tests/tfcompile_test.cc b/tensorflow/compiler/aot/tests/tfcompile_test.cc
index 6b037f276a..413efd9cea 100644
--- a/tensorflow/compiler/aot/tests/tfcompile_test.cc
+++ b/tensorflow/compiler/aot/tests/tfcompile_test.cc
@@ -70,7 +70,7 @@ TEST(TFCompileTest, Add) {
// Run tests that use set_argN_data separately, to avoid accidentally re-using
// non-existent buffers.
TEST(TFCompileTest, Add_SetArg) {
- AddComp add(AddComp::AllocMode::RESULTS_AND_TEMPS_ONLY);
+ AddComp add(AddComp::AllocMode::RESULTS_PROFILES_AND_TEMPS_ONLY);
int32 arg_x = 10;
int32 arg_y = 32;
@@ -258,7 +258,7 @@ TEST(TFCompileTest, MatMul2_SetArg) {
Eigen::ThreadPoolDevice device(&tp, tp.NumThreads());
foo::bar::MatMulComp matmul(
- foo::bar::MatMulComp::AllocMode::RESULTS_AND_TEMPS_ONLY);
+ foo::bar::MatMulComp::AllocMode::RESULTS_PROFILES_AND_TEMPS_ONLY);
matmul.set_thread_pool(&device);
// Test using the set_argN_data() methods.
diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc
index b5c17c5273..43d0e17c2c 100644
--- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc
+++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.cc
@@ -28,9 +28,10 @@ XlaCompiledCpuFunction::XlaCompiledCpuFunction(const StaticData& static_data,
temps_(new void*[static_data.num_temps]),
arg_names_(static_data.arg_names),
result_names_(static_data.result_names),
- program_shape_(static_data.program_shape) {
+ program_shape_(static_data.program_shape),
+ hlo_profile_printer_(static_data.hlo_profile_printer) {
// Allocate arg and temp buffers.
- if (alloc_mode == AllocMode::ARGS_RESULTS_AND_TEMPS) {
+ if (alloc_mode == AllocMode::ARGS_RESULTS_PROFILES_AND_TEMPS) {
alloc_args_ = tensorflow::tfcompile::runtime::MallocContiguousBuffers(
static_data.arg_sizes, static_data.num_args, args_,
/*annotate_initialized=*/false);
@@ -43,6 +44,15 @@ XlaCompiledCpuFunction::XlaCompiledCpuFunction(const StaticData& static_data,
if (static_data.requires_runtime_context) {
args_[static_data.num_args - 1] = &context_;
}
+
+ // If Hlo profiling is enabled the generated code expects an appropriately
+ // sized buffer to be passed in as the last argument. If Hlo profiling is
+ // disabled the last function argument is still present in the function
+ // signature, but it is ignored by the generated code and we pass in null for
+ // it.
+ if (hlo_profiling_enabled()) {
+ profile_counters_ = new int64[static_data.profile_counters_size]();
+ }
}
XlaCompiledCpuFunction::~XlaCompiledCpuFunction() {
@@ -50,6 +60,7 @@ XlaCompiledCpuFunction::~XlaCompiledCpuFunction() {
tensorflow::tfcompile::runtime::FreeContiguous(alloc_temps_);
delete[] args_;
delete[] temps_;
+ delete[] profile_counters_;
}
namespace {
diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
index f49a788922..3c4314d498 100644
--- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
+++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
@@ -16,7 +16,7 @@ limitations under the License.
#ifndef TENSORFLOW_COMPILER_TF2XLA_XLA_COMPILED_CPU_FUNCTION_H_
#define TENSORFLOW_COMPILER_TF2XLA_XLA_COMPILED_CPU_FUNCTION_H_
-#include <functional>
+#include <cassert>
#include <string>
#include "tensorflow/compiler/tf2xla/xla_local_runtime_context.h"
@@ -27,6 +27,7 @@ limitations under the License.
// never use this functionality.
namespace xla {
class ProgramShape;
+class HloProfilePrinter;
}
namespace tensorflow {
@@ -48,12 +49,10 @@ namespace tensorflow {
class XlaCompiledCpuFunction {
public:
// Type of the raw function, produced by either JIT or AOT.
- //
- // TODO(toddw): Add support for hlo profiling, and replace std::function with
- // a raw function pointer, for some codesize savings.
- using RawFunction = std::function<void(
- void* result, const xla::ExecutableRunOptions* run_options,
- const void** args, void** temps)>;
+ using RawFunction = void (*)(void* result,
+ const xla::ExecutableRunOptions* run_options,
+ const void** args, void** temps,
+ int64* profile_counters);
// StaticData represents the state necessary to run an XLA-compiled
// function. For JIT this is backed by data in XlaJitCompiledCpuFunction; for
@@ -81,21 +80,29 @@ class XlaCompiledCpuFunction {
// [Optional] Arg and result shapes.
const xla::ProgramShape* program_shape = nullptr;
+
+ // [Optional] Profile printer. Null if profiling is disabled.
+ const xla::HloProfilePrinter* hlo_profile_printer = nullptr;
+
+ // [Optional] The number of profile counters expected in the profile counter
+ // buffer by the generated code and hlo_profile_printer. 0 if profiling is
+ // disabled.
+ int64 profile_counters_size = 0;
};
// AllocMode controls the buffer allocation mode.
enum class AllocMode {
- // Allocate all buffers - args, results and temps.
- ARGS_RESULTS_AND_TEMPS,
+ // Allocate all buffers - args, results, profile and temps.
+ ARGS_RESULTS_PROFILES_AND_TEMPS,
- // Only allocate result and temp buffers.
+ // Only allocate result, profile and temp buffers.
// Use set_arg_data to set argument buffers before Run is called.
- RESULTS_AND_TEMPS_ONLY,
+ RESULTS_PROFILES_AND_TEMPS_ONLY,
};
XlaCompiledCpuFunction(
const StaticData& static_data,
- AllocMode alloc_mode = AllocMode::ARGS_RESULTS_AND_TEMPS);
+ AllocMode alloc_mode = AllocMode::ARGS_RESULTS_PROFILES_AND_TEMPS);
virtual ~XlaCompiledCpuFunction();
XlaCompiledCpuFunction(const XlaCompiledCpuFunction&) = delete;
@@ -113,7 +120,7 @@ class XlaCompiledCpuFunction {
context_.error = false;
context_.error_msg.clear();
raw_function_(temps_[result_index_], &run_options_,
- const_cast<const void**>(args_), temps_);
+ const_cast<const void**>(args_), temps_, profile_counters_);
return !context_.error;
}
@@ -162,6 +169,16 @@ class XlaCompiledCpuFunction {
return static_cast<const void* const*>(temps_[result_index_]);
}
+ // Profile counters for this XLA computation.
+ //
+ // When Hlo profiling is enabled (`hlo_profiling_enabled()` return true in
+ // this case) these counters are non-null and are automatically populated by
+ // `Run`. The counters can then be pretty-printed using
+ // `hlo_profile_printer()`.
+ //
+ // When Hlo profiling is disabled, this accessor returns null.
+ const int64* profile_counters() const { return profile_counters_; }
+
// Returns the buffer for the positional result at the given `index`.
void* result_data(size_t index) { return results()[index]; }
const void* result_data(size_t index) const { return results()[index]; }
@@ -195,6 +212,12 @@ class XlaCompiledCpuFunction {
// program shape isn't available.
const xla::ProgramShape* ProgramShape() const { return program_shape_; }
+ bool hlo_profiling_enabled() const { return hlo_profile_printer_ != nullptr; }
+ const xla::HloProfilePrinter& hlo_profile_printer() const {
+ assert(hlo_profiling_enabled());
+ return *hlo_profile_printer_;
+ }
+
private:
const RawFunction raw_function_;
const size_t result_index_;
@@ -208,6 +231,9 @@ class XlaCompiledCpuFunction {
void* alloc_args_ = nullptr;
void* alloc_temps_ = nullptr;
+ // Backing memory for profiling counters.
+ int64* profile_counters_ = nullptr;
+
// Options and context passed to the compiled function.
xla::ExecutableRunOptions run_options_;
tensorflow::XlaLocalRuntimeContext context_;
@@ -216,6 +242,7 @@ class XlaCompiledCpuFunction {
const char** arg_names_ = nullptr;
const char** result_names_ = nullptr;
const xla::ProgramShape* program_shape_ = nullptr;
+ const xla::HloProfilePrinter* hlo_profile_printer_ = nullptr;
};
} // namespace tensorflow
diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
index 1dd454ea8d..f727f20464 100644
--- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
+++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
@@ -90,21 +90,6 @@ xla::StatusOr<size_t> ComputeResultIndex(
return result_slice.index();
}
-// Adapt ComputeFunctionType, which includes a final profile_counters arg, to
-// RawFunction, which doesn't include that final arg.
-//
-// TODO(toddw): Change RawFunction and AOT to also pass the final
-// profile_counters arg, and remove this adapter.
-XlaCompiledCpuFunction::RawFunction RawFunctionAdapter(
- xla::cpu::CpuExecutable::ComputeFunctionType compute_function) {
- return [compute_function](void* result,
- const xla::ExecutableRunOptions* run_options,
- const void** args, void** temps) {
- return compute_function(result, run_options, args, temps,
- /*profile_counters=*/nullptr);
- };
-}
-
// Collect names from `entries`, where T is one of tf2xla::{Feed,Fetch}. We hold
// the actual strings in nonempty_names, and hold arrays of pointers in
// name_ptrs, terminated by a nullptr entry.
@@ -177,7 +162,7 @@ XlaJitCompiledCpuFunction::Compile(
const xla::cpu::CpuExecutable* cpu_executable =
static_cast<xla::cpu::CpuExecutable*>(executable->executable());
XlaCompiledCpuFunction::RawFunction raw_function =
- RawFunctionAdapter(cpu_executable->compute_function());
+ cpu_executable->compute_function();
const xla::BufferAssignment& buffer_assignment =
cpu_executable->buffer_assignment();
@@ -211,6 +196,14 @@ XlaJitCompiledCpuFunction::Compile(
jit->static_data_.arg_names = jit->arg_names_.data();
jit->static_data_.result_names = jit->result_names_.data();
jit->static_data_.program_shape = jit->program_shape_.get();
+
+ if (cpu_executable->hlo_profiling_enabled()) {
+ jit->static_data_.hlo_profile_printer =
+ &cpu_executable->hlo_profile_printer();
+ jit->static_data_.profile_counters_size =
+ cpu_executable->hlo_profile_printer().profile_counters_size();
+ }
+
return std::move(jit_unique_ptr);
}
diff --git a/tensorflow/compiler/xla/service/cpu/ir_function.cc b/tensorflow/compiler/xla/service/cpu/ir_function.cc
index fa88627156..701bce2cbf 100644
--- a/tensorflow/compiler/xla/service/cpu/ir_function.cc
+++ b/tensorflow/compiler/xla/service/cpu/ir_function.cc
@@ -99,7 +99,7 @@ void IrFunction::Initialize(const string& function_name,
//
// /---------------------------------------------\
// prof counters -> | counter 0 | counter 1 | ..... | counter N-1 |
- // (elided for aot) \---------------------------------------------/
+ // \---------------------------------------------/
// Even though the type of params and temps is void** in the host's view, in
// LLVM IR this is represented by i8*, similarly to void*. It's up to the code
diff --git a/tensorflow/compiler/xla/service/hlo_execution_profile.cc b/tensorflow/compiler/xla/service/hlo_execution_profile.cc
index ba75e2ef1b..0809fe780d 100644
--- a/tensorflow/compiler/xla/service/hlo_execution_profile.cc
+++ b/tensorflow/compiler/xla/service/hlo_execution_profile.cc
@@ -109,7 +109,8 @@ std::unique_ptr<HloProfilePrinter> CreateHloProfilePrinter(
};
return MakeUnique<HloProfilePrinter>(
- computation_infos, hlo_profile_index_map.computation_count(), deleter);
+ computation_infos, hlo_profile_index_map.computation_count(),
+ /*profile_counters_size=*/max_profile_index, deleter);
}
HloExecutionProfile::HloExecutionProfile(
diff --git a/tensorflow/compiler/xla/service/hlo_profile_printer.h b/tensorflow/compiler/xla/service/hlo_profile_printer.h
index 316753a82a..2f056490ae 100644
--- a/tensorflow/compiler/xla/service/hlo_profile_printer.h
+++ b/tensorflow/compiler/xla/service/hlo_profile_printer.h
@@ -65,9 +65,11 @@ class HloProfilePrinter {
HloProfilePrinter(
HloComputationInfo* computation_infos, int64 computation_infos_size,
+ int64 profile_counters_size,
std::function<void(HloComputationInfo*, int64)> deleter = nullptr)
: computation_infos_(computation_infos),
computation_infos_size_(computation_infos_size),
+ profile_counters_size_(profile_counters_size),
deleter_(std::move(deleter)) {}
HloProfilePrinter(HloProfilePrinter&& other) {
@@ -79,10 +81,13 @@ class HloProfilePrinter {
HloProfilePrinter(const HloProfilePrinter&) = delete;
HloProfilePrinter& operator=(const HloProfilePrinter&) = delete;
- // Convert the profile counter sequence `counters` to a human readable string
+ // Converts the profile counter sequence `counters` to a human readable string
// representation.
string ToString(const int64* counters, double clock_rate_ghz) const;
+ // Returns the size of the profile buffer expected by this printer.
+ int64 profile_counters_size() const { return profile_counters_size_; }
+
~HloProfilePrinter();
private:
@@ -90,6 +95,7 @@ class HloProfilePrinter {
// is manifested as the deleter_ function.
HloComputationInfo* computation_infos_ = nullptr;
int64 computation_infos_size_ = 0;
+ int64 profile_counters_size_ = 0;
std::function<void(HloComputationInfo*, int64)> deleter_;
};
} // namespace xla