Skip to content

Commit 87d6c94

Browse files
shoumikhinfacebook-github-bot
authored andcommitted
Require setting all inputs before execution.
Summary: Method never cared to check all the inputs were properly set before execution and basically used some default allocated memory for unset inputs. Here we introduce a safety check to guarantee users don't forget to set all inputs explicitly. Differential Revision: D79849134
1 parent afdbb85 commit 87d6c94

File tree

7 files changed

+152
-48
lines changed

7 files changed

+152
-48
lines changed

runtime/executor/method.cpp

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,21 @@ Error Method::parse_values(const NamedDataMap* external_data_map) {
407407
auto flatbuffer_values = serialization_plan_->values();
408408
ET_CHECK_OR_RETURN_ERROR(
409409
flatbuffer_values != nullptr, InvalidProgram, "Missing values");
410-
size_t n_value = flatbuffer_values->size();
410+
const size_t n_value = flatbuffer_values->size();
411411
values_ = memory_manager_->method_allocator()->allocateList<EValue>(n_value);
412412
if (values_ == nullptr) {
413413
return Error::MemoryAllocationFailed;
414414
}
415+
const size_t n_input = inputs_size();
416+
if (n_input > 0) {
417+
input_set_ = memory_manager_->method_allocator()->allocateList<bool>(n_input);
418+
if (input_set_ == nullptr) {
419+
return Error::MemoryAllocationFailed;
420+
}
421+
for (size_t i = 0; i < n_input; ++i) {
422+
input_set_[i] = false;
423+
}
424+
}
415425

416426
// Count the number of tensors marked as EXTERNAL for this method. The actual
417427
// number of external constants may be smaller, eg. if multiple tensors point
@@ -1076,26 +1086,21 @@ Method::set_input(const EValue& input_evalue, size_t input_idx) {
10761086
executorch::runtime::toString(t_src.scalar_type()));
10771087
// Reset the shape for the Method's input as the size of forwarded input
10781088
// tensor for shape dynamism. Also is a safety check if need memcpy.
1079-
Error err = resize_tensor(t_dst, t_src.sizes());
1080-
ET_CHECK_OR_RETURN_ERROR(
1081-
err == Error::Ok,
1082-
InvalidArgument,
1083-
"Error setting input %" ET_PRIsize_t ": 0x%" PRIx32,
1084-
input_idx,
1085-
static_cast<uint32_t>(err));
1086-
Error error;
1089+
ET_CHECK_OK_OR_RETURN_ERROR(
1090+
resize_tensor(t_dst, t_src.sizes()),
1091+
"Error resizing tensor at input %" ET_PRIsize_t, input_idx);
10871092
auto tensor_meta = this->method_meta().input_tensor_meta(input_idx);
10881093
if (tensor_meta->is_memory_planned()) {
1089-
error = internal::copy_tensor_data(t_dst, t_src);
1094+
ET_CHECK_OK_OR_RETURN_ERROR(
1095+
internal::copy_tensor_data(t_dst, t_src),
1096+
"Error setting copying tensor data at input %" ET_PRIsize_t, input_idx
1097+
);
10901098
} else {
1091-
error = internal::share_tensor_data(t_dst, t_src);
1099+
ET_CHECK_OK_OR_RETURN_ERROR(
1100+
internal::share_tensor_data(t_dst, t_src),
1101+
"Error setting sharing tensor data at input %" ET_PRIsize_t, input_idx
1102+
);
10921103
}
1093-
ET_CHECK_OR_RETURN_ERROR(
1094-
error == Error::Ok,
1095-
InvalidArgument,
1096-
"Error setting data_ptr %" ET_PRIsize_t ": 0x%" PRIx32,
1097-
input_idx,
1098-
static_cast<uint32_t>(error));
10991104
// Prims have to be the same as what was traced
11001105
} else if (e.isInt()) {
11011106
ET_CHECK_OR_RETURN_ERROR(
@@ -1163,35 +1168,16 @@ Method::set_input(const EValue& input_evalue, size_t input_idx) {
11631168

11641169
return Error::InvalidArgument;
11651170
}
1171+
input_set_[input_idx] = true;
1172+
11661173
return Error::Ok;
11671174
}
11681175

11691176
ET_NODISCARD Error
11701177
Method::set_inputs(const executorch::aten::ArrayRef<EValue>& input_evalues) {
1171-
ET_CHECK_OR_RETURN_ERROR(
1172-
initialized(),
1173-
InvalidState,
1174-
"Inputs can not be set until method has been initialized.");
1175-
1176-
ET_CHECK_OR_RETURN_ERROR(
1177-
step_state_.instr_idx == 0 && step_state_.chain_idx == 0,
1178-
InvalidState,
1179-
"Inputs can not be set mid execution.");
1180-
1181-
size_t input_size = inputs_size();
1182-
ET_CHECK_OR_RETURN_ERROR(
1183-
input_size == input_evalues.size(),
1184-
InvalidArgument,
1185-
"The length of given input array (%" ET_PRIsize_t
1186-
") must be same as the number of inputs in method (%" ET_PRIsize_t ").",
1187-
input_evalues.size(),
1188-
input_size);
1189-
1190-
for (size_t i = 0; i < input_size; i++) {
1191-
Error status = set_input(input_evalues[i], i);
1192-
if (status != Error::Ok) {
1193-
return status;
1194-
}
1178+
const size_t n_input = inputs_size();
1179+
for (size_t i = 0; i < n_input; ++i) {
1180+
ET_CHECK_OK_OR_RETURN_ERROR(set_input(input_evalues[i], i));
11951181
}
11961182
return Error::Ok;
11971183
}
@@ -1284,20 +1270,18 @@ ET_NODISCARD Error Method::get_inputs(EValue* input_evalues, size_t length) {
12841270
initialized(),
12851271
InvalidState,
12861272
"Inputs can not be retrieved until method has been initialized.");
1287-
1273+
const size_t n_input = inputs_size();
12881274
ET_CHECK_OR_RETURN_ERROR(
1289-
length >= inputs_size(),
1275+
length >= n_input,
12901276
InvalidArgument,
12911277
"The given array is not large enough to hold all inputs.");
12921278

1293-
for (size_t i = 0; i < inputs_size(); i++) {
1279+
for (size_t i = 0; i < n_input; ++i) {
12941280
input_evalues[i] = values_[get_input_index(i)];
12951281
}
1296-
1297-
for (size_t i = inputs_size(); i < length; i++) {
1282+
for (size_t i = n_input; i < length; ++i) {
12981283
input_evalues[i] = EValue();
12991284
}
1300-
13011285
return Error::Ok;
13021286
}
13031287

@@ -1545,6 +1529,14 @@ Error Method::execute() {
15451529
initialized(),
15461530
NotSupported,
15471531
"Cannot execute until method has been initialized.");
1532+
const size_t n_input = inputs_size();
1533+
for (size_t i = 0; i < n_input; ++i) {
1534+
ET_CHECK_OR_RETURN_ERROR(
1535+
input_set_[i],
1536+
InvalidArgument,
1537+
"Input %" ET_PRIsize_t " has not been set.", i
1538+
);
1539+
}
15481540
ET_LOG(Debug, "Executing method: %s.", method_meta().name());
15491541

15501542
// Chains are executed sequentially today, but future async designs may

runtime/executor/method.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class Method final {
7373
event_tracer_(rhs.event_tracer_),
7474
n_value_(rhs.n_value_),
7575
values_(rhs.values_),
76+
input_set_(rhs.input_set_),
7677
n_delegate_(rhs.n_delegate_),
7778
delegates_(rhs.delegates_),
7879
n_chains_(rhs.n_chains_),
@@ -85,6 +86,7 @@ class Method final {
8586
// anything twice.
8687
rhs.n_value_ = 0;
8788
rhs.values_ = nullptr;
89+
rhs.input_set_ = nullptr;
8890
rhs.n_delegate_ = 0;
8991
rhs.delegates_ = nullptr;
9092

@@ -314,6 +316,7 @@ class Method final {
314316
event_tracer_(event_tracer),
315317
n_value_(0),
316318
values_(nullptr),
319+
input_set_(nullptr),
317320
n_delegate_(0),
318321
delegates_(nullptr),
319322
n_chains_(0),
@@ -362,6 +365,7 @@ class Method final {
362365

363366
size_t n_value_;
364367
EValue* values_;
368+
bool* input_set_;
365369

366370
size_t n_delegate_;
367371
BackendDelegate* delegates_;

runtime/executor/test/allocation_failure_stress_test.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ TEST_F(AllocationFailureStressTest, End2EndIncreaseRuntimeMemUntilSuccess) {
8888
// once load was successful.
8989
auto input_cleanup = prepare_input_tensors(*method);
9090
ASSERT_EQ(input_cleanup.error(), Error::Ok);
91+
auto input_err =
92+
method->set_input(executorch::runtime::EValue(1.0), 2);
93+
ASSERT_EQ(input_err, Error::Ok);
9194
err = method->execute();
9295
ASSERT_EQ(err, Error::Ok);
9396
}
@@ -123,6 +126,9 @@ TEST_F(AllocationFailureStressTest, End2EndNonConstantMemUntilSuccess) {
123126
// once load was successful.
124127
auto input_cleanup = prepare_input_tensors(*method);
125128
ASSERT_EQ(input_cleanup.error(), Error::Ok);
129+
auto input_err =
130+
method->set_input(executorch::runtime::EValue(1.0), 2);
131+
ASSERT_EQ(input_err, Error::Ok);
126132
err = method->execute();
127133
ASSERT_EQ(err, Error::Ok);
128134
}

runtime/executor/test/backend_data_separation_test.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ TEST_F(BackendDataSeparationTest, TestSeparation) {
9595
/*named_data_map=*/linear_data_map_.get());
9696
ASSERT_EQ(method.error(), Error::Ok);
9797

98+
// Set a dummy input.
99+
int32_t sizes[1] = {3};
100+
uint8_t dim_order[1] = {0};
101+
int32_t strides[1] = {1};
102+
executorch::aten::TensorImpl impl(
103+
executorch::aten::ScalarType::Float,
104+
1,
105+
sizes,
106+
nullptr,
107+
dim_order,
108+
strides);
109+
auto input_err =
110+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
111+
ASSERT_EQ(input_err, Error::Ok);
112+
98113
// Can execute the method.
99114
Error err = method->execute();
100115
ASSERT_EQ(err, Error::Ok);

runtime/executor/test/backend_integration_test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,25 @@ TEST_P(BackendIntegrationTest, GetMethodNameDuringExecuteSuccess) {
603603
ManagedMemoryManager mmm(kDefaultNonConstMemBytes, kDefaultRuntimeMemBytes);
604604
Result<Method> method = program->load_method("forward", &mmm.get());
605605
EXPECT_TRUE(method.ok());
606+
607+
int32_t sizes[2] = {2, 2};
608+
uint8_t dim_order[2] = {0, 1};
609+
int32_t strides[2] = {2, 1};
610+
executorch::aten::TensorImpl impl(
611+
executorch::aten::ScalarType::Float,
612+
2,
613+
sizes,
614+
nullptr,
615+
dim_order,
616+
strides);
617+
auto input_err =
618+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
619+
input_err =
620+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 1);
621+
input_err =
622+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 2);
623+
ASSERT_EQ(input_err, Error::Ok);
624+
606625
Error err = method->execute();
607626
ASSERT_EQ(err, Error::Ok);
608627
}

runtime/executor/test/kernel_integration_test.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ class KernelIntegrationTest : public ::testing::Test {
248248
ASSERT_EQ(inputs_cleanup.error(), Error::Ok);
249249
inputs_cleanup_ = std::make_unique<executorch::extension::BufferCleanup>(
250250
std::move(*inputs_cleanup));
251+
auto input_err =
252+
method_->set_input(executorch::runtime::EValue(1.0), 2);
253+
ASSERT_EQ(input_err, Error::Ok);
251254
}
252255

253256
void TearDown() override {

runtime/executor/test/method_test.cpp

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,14 @@ TEST_F(MethodTest, MoveTest) {
104104
Result<Method> method = programs_["add"]->load_method("forward", &mmm.get());
105105
ASSERT_EQ(method.error(), Error::Ok);
106106

107-
// Can execute the method.
107+
// Set dummy inputs.
108108
auto input_cleanup = prepare_input_tensors(*method);
109109
ASSERT_EQ(input_cleanup.error(), Error::Ok);
110+
auto input_err =
111+
method->set_input(executorch::runtime::EValue(1.0), 2);
112+
ASSERT_EQ(input_err, Error::Ok);
113+
114+
// Can execute the method.
110115
Error err = method->execute();
111116
ASSERT_EQ(err, Error::Ok);
112117

@@ -312,6 +317,21 @@ TEST_F(MethodTest, ConstantSegmentTest) {
312317
programs_["add_mul"]->load_method("forward", &mmm.get());
313318
ASSERT_EQ(method.error(), Error::Ok);
314319

320+
// Set a dummy input.
321+
int32_t sizes[2] = {2, 2};
322+
uint8_t dim_order[2] = {0, 1};
323+
int32_t strides[2] = {2, 1};
324+
executorch::aten::TensorImpl impl(
325+
executorch::aten::ScalarType::Float,
326+
2,
327+
sizes,
328+
nullptr,
329+
dim_order,
330+
strides);
331+
auto input_err =
332+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
333+
ASSERT_EQ(input_err, Error::Ok);
334+
315335
// Can execute the method.
316336
Error err = method->execute();
317337
ASSERT_EQ(err, Error::Ok);
@@ -324,6 +344,21 @@ TEST_F(MethodTest, ConstantBufferTest) {
324344
programs_["linear_constant_buffer"]->load_method("forward", &mmm.get());
325345
ASSERT_EQ(method.error(), Error::Ok);
326346

347+
// Set a dummy input.
348+
int32_t sizes[2] = {2, 2};
349+
uint8_t dim_order[2] = {0, 1};
350+
int32_t strides[2] = {2, 1};
351+
executorch::aten::TensorImpl impl(
352+
executorch::aten::ScalarType::Float,
353+
2,
354+
sizes,
355+
nullptr,
356+
dim_order,
357+
strides);
358+
auto input_err =
359+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
360+
ASSERT_EQ(input_err, Error::Ok);
361+
327362
// Can execute the method.
328363
Error err = method->execute();
329364
ASSERT_EQ(err, Error::Ok);
@@ -335,6 +370,21 @@ TEST_F(MethodTest, ProgramDataSeparationTest) {
335370
"forward", &mmm.get(), nullptr, data_maps_["add_mul_data"].get());
336371
ASSERT_EQ(method.error(), Error::Ok);
337372

373+
// Set a dummy input.
374+
int32_t sizes[2] = {2, 2};
375+
uint8_t dim_order[2] = {0, 1};
376+
int32_t strides[2] = {2, 1};
377+
executorch::aten::TensorImpl impl(
378+
executorch::aten::ScalarType::Float,
379+
2,
380+
sizes,
381+
nullptr,
382+
dim_order,
383+
strides);
384+
auto input_err =
385+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
386+
ASSERT_EQ(input_err, Error::Ok);
387+
338388
// Can execute the method.
339389
Error err = method->execute();
340390
ASSERT_EQ(err, Error::Ok);
@@ -357,6 +407,21 @@ TEST_F(MethodTest, MethodGetAttributeTest) {
357407
// expect data to be set
358408
EXPECT_EQ(res->const_data_ptr(), &data);
359409

410+
// Set a dummy input.
411+
int32_t sizes[1] = {1};
412+
uint8_t dim_order[1] = {0};
413+
int32_t strides[1] = {1};
414+
executorch::aten::TensorImpl impl(
415+
executorch::aten::ScalarType::Float,
416+
1,
417+
sizes,
418+
nullptr,
419+
dim_order,
420+
strides);
421+
auto input_err =
422+
method->set_input(executorch::runtime::EValue(executorch::aten::Tensor(&impl)), 0);
423+
ASSERT_EQ(input_err, Error::Ok);
424+
360425
// Can execute the method.
361426
Error err = method->execute();
362427
ASSERT_EQ(err, Error::Ok);

0 commit comments

Comments
 (0)