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;
2930using ::executorch::runtime::EValue;
3031using ::executorch::runtime::EventTracerEntry;
3132using ::executorch::runtime::LoggedEValueType;
33+ using ::executorch::runtime::Result;
3234using ::executorch::runtime::Span;
3335using ::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
499501void 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
517509void 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
0 commit comments