Skip to content

Commit 58161bb

Browse files
committed
[devtool] introduce sanity check when creating bufferdatasink
This diff introduces sanity check on data alignment when creating buffer_data_sink. Also, for better control the raised error, we changed to use static function instead of constructor for constuction. Differential Revision: [D70190912](https://our.internmc.facebook.com/intern/diff/D70190912/) [ghstack-poisoned]
1 parent 93838e8 commit 58161bb

File tree

3 files changed

+72
-13
lines changed

3 files changed

+72
-13
lines changed

devtools/etdump/buffer_data_sink.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,22 @@
1111

1212
using ::executorch::runtime::Error;
1313
using ::executorch::runtime::Result;
14+
using ::executorch::runtime::Span;
1415

1516
namespace executorch {
1617
namespace etdump {
1718

19+
Result<BufferDataSink> BufferDataSink::create(
20+
Span<uint8_t> buffer,
21+
size_t alignment) noexcept {
22+
// Check if alignment is a power of two and greater than 0
23+
if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
24+
return Error::InvalidArgument;
25+
}
26+
27+
return BufferDataSink(buffer, alignment);
28+
}
29+
1830
Result<size_t> BufferDataSink::write(const void* ptr, size_t length) {
1931
if (length == 0) {
2032
return offset_;

devtools/etdump/buffer_data_sink.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,20 @@ namespace etdump {
2424
class BufferDataSink : public DataSinkBase {
2525
public:
2626
/**
27-
* Constructs a BufferDataSink with a given buffer.
27+
* Creates a BufferDataSink with a given span buffer.
2828
*
2929
* @param[in] buffer A Span object representing the buffer where data will be
3030
* stored.
3131
* @param[in] alignment The alignment requirement for the buffer. It must be
32-
* a power of two. Default is 64.
32+
* a power of two and greater than zero. Default is 64.
33+
* @return A Result object containing either:
34+
* - A BufferDataSink object if succees, or
35+
* - An error code indicating the failure reason, if any issue
36+
* occurs during the creation process.
3337
*/
34-
explicit BufferDataSink(
38+
static ::executorch::runtime::Result<BufferDataSink> create(
3539
::executorch::runtime::Span<uint8_t> buffer,
36-
size_t alignment = 64)
37-
: debug_buffer_(buffer), offset_(0), alignment_(alignment) {}
40+
size_t alignment = 64) noexcept;
3841

3942
// Uncopiable and unassignable to avoid double assignment and free of the
4043
// internal buffer.
@@ -77,6 +80,19 @@ class BufferDataSink : public DataSinkBase {
7780
size_t get_used_bytes() const override;
7881

7982
private:
83+
/**
84+
* Constructs a BufferDataSink with a given buffer.
85+
*
86+
* @param[in] buffer A Span object representing the buffer where data will be
87+
* stored.
88+
* @param[in] alignment The alignment requirement for the buffer. It must be
89+
* a power of two. Default is 64.
90+
*/
91+
explicit BufferDataSink(
92+
::executorch::runtime::Span<uint8_t> buffer,
93+
size_t alignment)
94+
: debug_buffer_(buffer), offset_(0), alignment_(alignment) {}
95+
8096
// A Span object representing the buffer used for storing debug data.
8197
::executorch::runtime::Span<uint8_t> debug_buffer_;
8298

devtools/etdump/tests/buffer_data_sink_test.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using namespace ::testing;
1717
using ::executorch::aten::ScalarType;
1818
using ::executorch::aten::Tensor;
19+
using ::executorch::etdump::BufferDataSink;
1920
using ::executorch::runtime::Error;
2021
using ::executorch::runtime::Result;
2122
using ::executorch::runtime::Span;
@@ -29,7 +30,6 @@ class BufferDataSinkTest : public ::testing::Test {
2930
buffer_size_ = 128; // Small size for testing
3031
buffer_ptr_ = malloc(buffer_size_);
3132
buffer_ = Span<uint8_t>(static_cast<uint8_t*>(buffer_ptr_), buffer_size_);
32-
data_sink_ = std::make_unique<executorch::etdump::BufferDataSink>(buffer_);
3333
}
3434

3535
void TearDown() override {
@@ -39,11 +39,13 @@ class BufferDataSinkTest : public ::testing::Test {
3939
size_t buffer_size_;
4040
void* buffer_ptr_;
4141
Span<uint8_t> buffer_;
42-
std::unique_ptr<executorch::etdump::BufferDataSink> data_sink_;
4342
};
4443

4544
TEST_F(BufferDataSinkTest, StorageSizeCheck) {
46-
Result<size_t> ret = data_sink_->get_storage_size();
45+
Result<BufferDataSink> buffer_data_sink = BufferDataSink::create(buffer_);
46+
ASSERT_EQ(buffer_data_sink.error(), Error::Ok);
47+
48+
Result<size_t> ret = buffer_data_sink.get().get_storage_size();
4749
ASSERT_EQ(ret.error(), Error::Ok);
4850

4951
size_t storage_size = ret.get();
@@ -54,8 +56,10 @@ TEST_F(BufferDataSinkTest, WriteOneTensorAndCheckData) {
5456
TensorFactory<ScalarType::Float> tf;
5557
Tensor tensor = tf.make({1, 4}, {1.0, 2.0, 3.0, 4.0});
5658

59+
Result<BufferDataSink> buffer_data_sink = BufferDataSink::create(buffer_);
60+
5761
Result<size_t> ret =
58-
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
62+
buffer_data_sink->write(tensor.const_data_ptr(), tensor.nbytes());
5963
ASSERT_EQ(ret.error(), Error::Ok);
6064

6165
size_t offset = ret.get();
@@ -75,9 +79,11 @@ TEST_F(BufferDataSinkTest, WriteMultiTensorsAndCheckData) {
7579
std::vector<Tensor> tensors = {
7680
tf.make({1, 4}, {1.0, 2.0, 3.0, 4.0}),
7781
tf.make({1, 4}, {5.0, 6.0, 7.0, 8.0})};
82+
Result<BufferDataSink> buffer_data_sink = BufferDataSink::create(buffer_);
83+
7884
for (const auto& tensor : tensors) {
7985
Result<size_t> ret =
80-
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
86+
buffer_data_sink->write(tensor.const_data_ptr(), tensor.nbytes());
8187
ASSERT_EQ(ret.error(), Error::Ok);
8288

8389
size_t offset = ret.get();
@@ -94,8 +100,10 @@ TEST_F(BufferDataSinkTest, WriteMultiTensorsAndCheckData) {
94100
TEST_F(BufferDataSinkTest, PointerAlignmentCheck) {
95101
TensorFactory<ScalarType::Float> tf;
96102
Tensor tensor = tf.make({1, 4}, {1.0, 2.0, 3.0, 4.0});
103+
Result<BufferDataSink> buffer_data_sink = BufferDataSink::create(buffer_);
104+
97105
Result<size_t> ret =
98-
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
106+
buffer_data_sink->write(tensor.const_data_ptr(), tensor.nbytes());
99107
ASSERT_EQ(ret.error(), Error::Ok);
100108

101109
size_t offset = ret.get();
@@ -109,15 +117,38 @@ TEST_F(BufferDataSinkTest, WriteUntilOverflow) {
109117
TensorFactory<ScalarType::Float> tf;
110118
Tensor tensor = tf.zeros({1, 8}); // Large tensor to fill the buffer
111119

120+
Result<BufferDataSink> buffer_data_sink = BufferDataSink::create(buffer_);
121+
112122
// Write tensors until we run out of space
113123
for (size_t i = 0; i < 2; i++) {
114124
Result<size_t> ret =
115-
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
125+
buffer_data_sink->write(tensor.const_data_ptr(), tensor.nbytes());
116126
ASSERT_EQ(ret.error(), Error::Ok);
117127
}
118128

119129
// Attempting to write another tensor should raise an error
120130
Result<size_t> ret =
121-
data_sink_->write(tensor.const_data_ptr(), tensor.nbytes());
131+
buffer_data_sink->write(tensor.const_data_ptr(), tensor.nbytes());
122132
ASSERT_EQ(ret.error(), Error::OutOfResources);
123133
}
134+
135+
TEST_F(BufferDataSinkTest, illegalAlignment) {
136+
for (size_t i = 1; i <= 128; i <<= 1) {
137+
// Create a buffer_data_sink with legal alignment that is a power of 2 and
138+
// greater than 0
139+
Result<BufferDataSink> buffer_data_sink =
140+
BufferDataSink::create(buffer_, i);
141+
ASSERT_EQ(buffer_data_sink.error(), Error::Ok);
142+
}
143+
144+
// Create a buffer_data_sink with illegal alignment that is not a power of 2
145+
// or greater than 0
146+
147+
std::vector<size_t> illegal_alignments = {0, 3, 5, 7, 100, 127};
148+
149+
for (size_t i = 0; i < illegal_alignments.size(); i++) {
150+
Result<BufferDataSink> buffer_data_sink =
151+
BufferDataSink::create(buffer_, illegal_alignments[i]);
152+
ASSERT_EQ(buffer_data_sink.error(), Error::InvalidArgument);
153+
}
154+
}

0 commit comments

Comments
 (0)