Skip to content

Commit 6d0b24d

Browse files
committed
[devtool] make ETDumpGen use bufferdatasink
Pull Request resolved: #8499 This diff enables customized debug data pipeline by making ETDumpGen leverage user-provided datasink. Details can be found in https://docs.google.com/document/d/1y_m32mKdj-OgLcLUz9TKhBW3PC3bBDYSBbeAH544EfM/edit?tab=t.0#heading=h.jlkcrurw482r ghstack-source-id: 268447337 @exported-using-ghexport Differential Revision: [D69647096](https://our.internmc.facebook.com/intern/diff/D69647096/)
1 parent bc55c01 commit 6d0b24d

File tree

8 files changed

+333
-228
lines changed

8 files changed

+333
-228
lines changed

devtools/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ add_custom_command(
176176
add_library(
177177
etdump ${CMAKE_CURRENT_SOURCE_DIR}/etdump/etdump_flatcc.cpp
178178
${CMAKE_CURRENT_SOURCE_DIR}/etdump/emitter.cpp
179+
${CMAKE_CURRENT_SOURCE_DIR}/etdump/buffer_data_sink.cpp
180+
${CMAKE_CURRENT_SOURCE_DIR}/etdump/buffer_data_sink.h
179181
)
180182

181183
target_link_libraries(

devtools/etdump/buffer_data_sink.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ Result<BufferDataSink> BufferDataSink::create(
2727
return BufferDataSink(buffer, alignment);
2828
}
2929

30+
Result<BufferDataSink> BufferDataSink::create(
31+
void* ptr, size_t size,
32+
size_t alignment) noexcept {
33+
return BufferDataSink::create({(uint8_t*)ptr, size}, alignment);
34+
}
35+
3036
Result<size_t> BufferDataSink::write(const void* ptr, size_t length) {
3137
if (length == 0) {
3238
return offset_;

devtools/etdump/buffer_data_sink.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ class BufferDataSink : public DataSinkBase {
3939
::executorch::runtime::Span<uint8_t> buffer,
4040
size_t alignment = 64) noexcept;
4141

42+
/**
43+
* Creates a BufferDataSink with a given span buffer.
44+
*
45+
* @param[in] ptr A pointer to the data blob where data will be stored.
46+
* @param[in] size The size of the data blob in bytes.
47+
* @param[in] alignment The alignment requirement for the buffer. It must be
48+
* a power of two and greater than zero. Default is 64.
49+
* @return A Result object containing either:
50+
* - A BufferDataSink object if succees, or
51+
* - An error code indicating the failure reason, if any issue
52+
* occurs during the creation process.
53+
*/
54+
static ::executorch::runtime::Result<BufferDataSink> create(
55+
void* ptr, size_t size,
56+
size_t alignment = 64) noexcept;
57+
4258
// Uncopiable and unassignable to avoid double assignment and free of the
4359
// internal buffer.
4460
BufferDataSink(const BufferDataSink&) = delete;

devtools/etdump/etdump_flatcc.cpp

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <cstring>
1212

13+
#include <executorch/devtools/etdump/buffer_data_sink.h>
1314
#include <executorch/devtools/etdump/emitter.h>
1415
#include <executorch/devtools/etdump/etdump_schema_flatcc_builder.h>
1516
#include <executorch/devtools/etdump/etdump_schema_flatcc_reader.h>
@@ -29,6 +30,7 @@ using ::executorch::runtime::DelegateDebugIdType;
2930
using ::executorch::runtime::EValue;
3031
using ::executorch::runtime::EventTracerEntry;
3132
using ::executorch::runtime::LoggedEValueType;
33+
using ::executorch::runtime::Result;
3234
using ::executorch::runtime::Span;
3335
using ::executorch::runtime::Tag;
3436

@@ -347,10 +349,10 @@ void ETDumpGen::log_intermediate_output_delegate_helper(
347349
ET_CHECK_MSG(
348350
(name == nullptr) ^ (delegate_debug_index == -1),
349351
"Only name or delegate_debug_index can be valid. Check DelegateMappingBuilder documentation for more details.");
350-
if (debug_buffer_.empty()) {
351-
ET_CHECK_MSG(0, "Must pre-set debug buffer with set_debug_buffer()\n");
352-
return;
353-
}
352+
353+
ET_CHECK_MSG(
354+
data_sink_,
355+
"Must pre-set data sink before logging evalue with set_data_sink() or set_debug_buffer()\n");
354356

355357
check_ready_to_add_events();
356358
int64_t string_id = name != nullptr ? create_string_entry(name) : -1;
@@ -367,7 +369,7 @@ void ETDumpGen::log_intermediate_output_delegate_helper(
367369

368370
// Check the type of `output` then call the corresponding logging functions
369371
if constexpr (std::is_same<T, Tensor>::value) {
370-
long offset = copy_tensor_to_debug_buffer(output);
372+
long offset = write_tensor_or_raise_error(output);
371373
etdump_Tensor_ref_t tensor_ref = add_tensor_entry(builder_, output, offset);
372374

373375
etdump_Value_start(builder_);
@@ -377,7 +379,7 @@ void ETDumpGen::log_intermediate_output_delegate_helper(
377379
} else if constexpr (std::is_same<T, ArrayRef<Tensor>>::value) {
378380
etdump_Tensor_vec_start(builder_);
379381
for (size_t i = 0; i < output.size(); ++i) {
380-
long offset = copy_tensor_to_debug_buffer(output[i]);
382+
long offset = write_tensor_or_raise_error(output[i]);
381383
etdump_Tensor_vec_push(
382384
builder_, add_tensor_entry(builder_, output[i], offset));
383385
}
@@ -497,27 +499,15 @@ ETDumpResult ETDumpGen::get_etdump_data() {
497499
}
498500

499501
void ETDumpGen::set_debug_buffer(Span<uint8_t> buffer) {
500-
debug_buffer_ = buffer;
502+
data_sink_ = std::make_shared<BufferDataSink>(std::move(BufferDataSink::create(buffer).get()));
501503
}
502504

503-
size_t ETDumpGen::copy_tensor_to_debug_buffer(executorch::aten::Tensor tensor) {
504-
if (tensor.nbytes() == 0) {
505-
return static_cast<size_t>(-1);
506-
}
507-
uint8_t* offset_ptr =
508-
internal::align_pointer(debug_buffer_.data() + debug_buffer_offset_, 64);
509-
debug_buffer_offset_ = (offset_ptr - debug_buffer_.data()) + tensor.nbytes();
510-
ET_CHECK_MSG(
511-
debug_buffer_offset_ <= debug_buffer_.size(),
512-
"Ran out of space to store intermediate outputs.");
513-
memcpy(offset_ptr, tensor.const_data_ptr(), tensor.nbytes());
514-
return (size_t)(offset_ptr - debug_buffer_.data());
505+
void ETDumpGen::set_data_sink(std::shared_ptr<DataSinkBase> buffer_data_sink) {
506+
data_sink_ = buffer_data_sink;
515507
}
516508

517509
void ETDumpGen::log_evalue(const EValue& evalue, LoggedEValueType evalue_type) {
518-
if (debug_buffer_.empty()) {
519-
return;
520-
}
510+
ET_CHECK_MSG(data_sink_, "Must set data sink before logging evalue\n");
521511

522512
check_ready_to_add_events();
523513

@@ -529,7 +519,7 @@ void ETDumpGen::log_evalue(const EValue& evalue, LoggedEValueType evalue_type) {
529519
switch (evalue.tag) {
530520
case Tag::Tensor: {
531521
executorch::aten::Tensor tensor = evalue.toTensor();
532-
long offset = copy_tensor_to_debug_buffer(tensor);
522+
long offset = write_tensor_or_raise_error(tensor);
533523
etdump_Tensor_ref_t tensor_ref =
534524
add_tensor_entry(builder_, tensor, offset);
535525

@@ -551,7 +541,7 @@ void ETDumpGen::log_evalue(const EValue& evalue, LoggedEValueType evalue_type) {
551541
evalue.toTensorList();
552542
etdump_Tensor_vec_start(builder_);
553543
for (size_t i = 0; i < tensors.size(); ++i) {
554-
long offset = copy_tensor_to_debug_buffer(tensors[i]);
544+
long offset = write_tensor_or_raise_error(tensors[i]);
555545
etdump_Tensor_vec_push(
556546
builder_, add_tensor_entry(builder_, tensors[i], offset));
557547
}
@@ -635,8 +625,31 @@ bool ETDumpGen::is_static_etdump() {
635625
return alloc_.data != nullptr;
636626
}
637627

638-
size_t ETDumpGen::get_debug_buffer_size() const {
639-
return debug_buffer_.size();
628+
std::shared_ptr<DataSinkBase> ETDumpGen::get_data_sink() {
629+
return data_sink_;
630+
}
631+
632+
long ETDumpGen::write_tensor_or_raise_error(Tensor tensor) {
633+
// Previously, the function copy_tensor_to_debug_buffer returned 0xFF..F when
634+
// given an empty tensor, which is an invalid offset for most buffers. In our
635+
// data sink, we will return the current debug_buffer_offset for better
636+
// clarity. We are isolating the empty tensor case here using the old logic to
637+
// avoid any backward compatibility issues while introducing the data sink.
638+
// Once the data sink is fully implemented, we can remove this check and apply
639+
// the new logic to all cases.
640+
// TODO(gasoonjia): remove this check after datasink is fully rolled out.
641+
if (tensor.nbytes() == 0) {
642+
return static_cast<size_t>(-1);
643+
}
644+
645+
ET_CHECK_MSG(data_sink_, "Must set data sink before writing data");
646+
Result<size_t> ret =
647+
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
648+
ET_CHECK_MSG(
649+
ret.ok(),
650+
"Failed to write tensor with error 0x%" PRIx32,
651+
static_cast<uint32_t>(ret.error()));
652+
return static_cast<long>(ret.get());
640653
}
641654

642655
} // namespace etdump

devtools/etdump/etdump_flatcc.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#pragma once
1010

1111
#include <cstdint>
12+
#include <memory>
1213

14+
#include <executorch/devtools/etdump/data_sink_base.h>
1315
#include <executorch/runtime/core/event_tracer.h>
1416
#include <executorch/runtime/core/span.h>
1517
#include <executorch/runtime/platform/platform.h>
@@ -141,9 +143,10 @@ class ETDumpGen : public ::executorch::runtime::EventTracer {
141143
::executorch::runtime::DebugHandle delegate_debug_index,
142144
const double& output) override;
143145
void set_debug_buffer(::executorch::runtime::Span<uint8_t> buffer);
146+
void set_data_sink(std::shared_ptr<DataSinkBase> buffer_data_sink);
144147
ETDumpResult get_etdump_data();
145-
size_t get_debug_buffer_size() const;
146148
size_t get_num_blocks();
149+
std::shared_ptr<DataSinkBase> get_data_sink();
147150
bool is_static_etdump();
148151
void reset();
149152

@@ -158,7 +161,6 @@ class ETDumpGen : public ::executorch::runtime::EventTracer {
158161

159162
void check_ready_to_add_events();
160163
int64_t create_string_entry(const char* name);
161-
size_t copy_tensor_to_debug_buffer(executorch::aten::Tensor tensor);
162164

163165
/**
164166
* Templated helper function used to log various types of intermediate output.
@@ -170,10 +172,11 @@ class ETDumpGen : public ::executorch::runtime::EventTracer {
170172
::executorch::runtime::DebugHandle delegate_debug_index,
171173
const T& output);
172174

175+
long write_tensor_or_raise_error(executorch::aten::Tensor tensor);
176+
173177
struct flatcc_builder* builder_;
174178
size_t num_blocks_ = 0;
175-
::executorch::runtime::Span<uint8_t> debug_buffer_;
176-
size_t debug_buffer_offset_ = 0;
179+
std::shared_ptr<DataSinkBase> data_sink_;
177180
int bundled_input_index_ = -1;
178181
State state_ = State::Init;
179182
struct internal::ETDumpStaticAllocator alloc_;

devtools/etdump/targets.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def define_common_targets():
117117

118118
runtime.cxx_library(
119119
name = "buffer_data_sink" + aten_suffix,
120-
headers = [
120+
exported_headers = [
121121
"buffer_data_sink.h",
122122
],
123123
srcs = [
@@ -153,6 +153,8 @@ def define_common_targets():
153153
exported_deps = [
154154
":etdump_schema_flatcc",
155155
":utils",
156+
":data_sink_base" + aten_suffix,
157+
":buffer_data_sink" + aten_suffix,
156158
"//executorch/runtime/core:event_tracer" + aten_suffix,
157159
"//executorch/runtime/core/exec_aten/util:scalar_type_util" + aten_suffix,
158160
],

0 commit comments

Comments
 (0)