Skip to content

Commit 329b9ff

Browse files
GregoryComerfacebook-github-bot
authored andcommitted
Improve error messages for tensor size errors
Summary: Print expected and actual tensor sizes when attempting to resize a static tensor. This commonly comes up when a user provides an incorrectly-shaped input tensor and can be confusing. Adding the expected and actual sizes should make this situation more intuitive. This change also includes ET_UNUSED in several places where the variable is used only when logging is enabled, as unused variable warnings cause build failures in some build modes when logging is disabled. Differential Revision: D67665846
1 parent fc04436 commit 329b9ff

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

runtime/core/exec_aten/util/dim_order_util.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#pragma once
1010

1111
#include <cstdint>
12+
#include <cstdio>
13+
#include <cstring>
1214

1315
#include <executorch/runtime/core/error.h>
1416
#include <executorch/runtime/platform/assert.h>
@@ -257,6 +259,33 @@ ET_NODISCARD inline Error stride_to_dim_order(
257259
}
258260
return Error::Ok;
259261
}
262+
263+
/**
264+
* Print a string representation of an ArrayRef of tensor sizes into a
265+
* user-provided string buffer. If the user buffer is too small, the string
266+
* will be truncated. The output is of the format (1,2,3,4).
267+
*
268+
* Note that we cannot use ArrayRef here due to a circular dependency (see
269+
* above comments).
270+
*/
271+
template <class SizesType>
272+
inline void sizes_to_string(char* output, size_t output_size, SizesType* sizes, size_t rank) {
273+
auto remaining_size = output_size;
274+
for (auto i = 0; remaining_size > 0 && i < rank; i++) {
275+
snprintf(
276+
output,
277+
remaining_size,
278+
"%s%zd",
279+
i == 0 ? "(" : ",",
280+
static_cast<size_t>(sizes[i]));
281+
auto len = strlen(output);
282+
output += len;
283+
remaining_size -= len;
284+
}
285+
snprintf(output, remaining_size, ")");
286+
}
287+
288+
260289
} // namespace runtime
261290
} // namespace executorch
262291

runtime/core/portable_type/tensor_impl.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,24 +90,42 @@ Error TensorImpl::internal_resize_contiguous(ArrayRef<SizesType> new_sizes) {
9090
if (dim_ == 0) {
9191
return Error::Ok;
9292
}
93+
94+
const auto new_numel = compute_numel(new_sizes.data(), dim_);
95+
9396
switch (shape_dynamism_) {
9497
case TensorShapeDynamism::STATIC:
95-
ET_CHECK_OR_RETURN_ERROR(
96-
std::equal(sizes_, sizes_ + dim_, new_sizes.begin()),
97-
NotSupported,
98-
"Attempted to resize a static tensor");
98+
{
99+
auto is_equal = std::equal(sizes_, sizes_ + dim_, new_sizes.begin());
100+
101+
if (!is_equal) {
102+
#ifdef ET_LOG_ENABLED
103+
std::array<char, 24> old_sizes_str, new_sizes_str;
104+
105+
executorch::runtime::sizes_to_string(old_sizes_str.data(), old_sizes_str.size(), sizes().data(), sizes().size());
106+
executorch::runtime::sizes_to_string(new_sizes_str.data(), new_sizes_str.size(), new_sizes.data(), new_sizes.size());
107+
#endif
108+
109+
ET_CHECK_OR_RETURN_ERROR(
110+
is_equal,
111+
NotSupported,
112+
"Attempted to resize a static tensor. Expected shape %s, but received %s.",
113+
old_sizes_str.data(),
114+
new_sizes_str.data())
115+
}
116+
99117
break;
118+
}
100119
case TensorShapeDynamism::DYNAMIC_BOUND:
101120
// TODO(T175194371): Unbounded dynamic tensor resizing is not yet
102121
// supported: treat them as upper-bounded.
103122
case TensorShapeDynamism::DYNAMIC_UNBOUND: {
104-
const auto new_numel = compute_numel(new_sizes.data(), dim_);
105123
ET_CHECK_OR_RETURN_ERROR(
106124
new_numel <= numel_bound_,
107125
NotSupported,
108-
"Attempted to resize a bounded tensor with capacity of %zu elements to %zu elements.",
109-
new_numel,
110-
numel_bound_);
126+
"Attempted to resize a bounded tensor with a maximum capacity of %zu elements to %zu elements.",
127+
numel_bound_,
128+
new_numel);
111129

112130
if (strides_ && dim_order_) {
113131
auto error =

runtime/executor/method.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ Error Method::execute_instruction() {
10611061
// We know that instr_args_as_KernelCall is non-null because it was
10621062
// checked at init time.
10631063
auto op_index = instruction->instr_args_as_KernelCall()->op_index();
1064-
auto op = serialization_plan_->operators()->Get(op_index);
1064+
ET_UNUSED auto op = serialization_plan_->operators()->Get(op_index);
10651065
ET_LOG(
10661066
Error,
10671067
"KernelCall failed at instruction %zu:%zu in operator %s.%s: 0x%x",

runtime/kernel/operator_registry.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Error register_kernels_internal(const Span<const Kernel> kernels) {
7474
return Error::Internal;
7575
}
7676
// for debugging purpose
77-
const char* lib_name = et_pal_get_shared_library_name(kernels.data());
77+
ET_UNUSED const char* lib_name = et_pal_get_shared_library_name(kernels.data());
7878

7979
for (const auto& kernel : kernels) {
8080
// Linear search. This is fine if the number of kernels is small.

0 commit comments

Comments
 (0)