Skip to content

Commit f2c4915

Browse files
committed
Add function to stringify tensor shapes
First step toward fixing #7902 ghstack-source-id: d869c4e ghstack-comment-id: 2613189307 Pull Request resolved: #7943
1 parent c361431 commit f2c4915

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

runtime/core/exec_aten/util/targets.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def define_common_targets():
5050

5151
runtime.cxx_library(
5252
name = "tensor_util" + aten_suffix,
53-
srcs = ["tensor_util_aten.cpp"] if aten_mode else ["tensor_util_portable.cpp"],
53+
srcs = ["tensor_util.cpp"] + (["tensor_util_aten.cpp"] if aten_mode else ["tensor_util_portable.cpp"]),
5454
exported_headers = [
5555
"tensor_util.h",
5656
],
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include "tensor_util.h"
2+
3+
/*
4+
* Copyright (c) Meta Platforms, Inc. and affiliates.
5+
* All rights reserved.
6+
*
7+
* This source code is licensed under the BSD-style license found in the
8+
* LICENSE file in the root directory of this source tree.
9+
*/
10+
11+
#include <executorch/runtime/core/exec_aten/util/tensor_util.h>
12+
13+
#include <executorch/runtime/platform/assert.h>
14+
15+
namespace executorch::runtime {
16+
/**
17+
* Shared implementation for tensor_util.h, may only contain code that
18+
* works whether or not ATen mode is active.
19+
*/
20+
std::array<char, kTensorShapeStringSizeLimit> tensor_shape_to_c_string(
21+
executorch::aten::ArrayRef<executorch::aten::SizesType> shape) {
22+
std::array<char, kTensorShapeStringSizeLimit> out;
23+
char* p = out.data();
24+
*p++ = '(';
25+
for (const auto elem : shape) {
26+
if (elem < 0 || elem > kMaximumPrintableTensorShapeElement) {
27+
strcpy(p, "ERR, ");
28+
p += strlen("ERR, ");
29+
} else {
30+
// snprintf returns characters *except* the NUL terminator, which is what
31+
// we want.
32+
p += snprintf(
33+
p,
34+
kTensorShapeStringSizeLimit - (p - out.data()),
35+
"%" PRIu32 ", ",
36+
static_cast<uint32_t>(elem));
37+
}
38+
}
39+
*(p - 2) = ')';
40+
*(p - 1) = '\0';
41+
return out;
42+
}
43+
44+
} // namespace executorch::runtime

runtime/core/exec_aten/util/tensor_util.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,28 @@ bool extract_scalar_tensor(executorch::aten::Tensor tensor, BOOL_T* out_val) {
11201120
return true;
11211121
}
11221122

1123+
/**
1124+
* Maximum size of a string returned by tensor_shape_to_c_string, for
1125+
* stack allocation.
1126+
*/
1127+
constexpr size_t kTensorShapeStringSizeLimit = 1 + /* opening parenthesis */
1128+
10 * kTensorDimensionLimit + /* maximum digits we will print; update
1129+
* kMaximumPrintableTensorShapeElement
1130+
* if changing */
1131+
2 * kTensorDimensionLimit + /* comma and space after each item,
1132+
* overwritten with closing paren and
1133+
* NUL terminator for last element */
1134+
1; /* padding for temporary NUL terminator for simplicity of implementation
1135+
*/
1136+
1137+
constexpr size_t kMaximumPrintableTensorShapeElement =
1138+
std::is_same_v<executorch::aten::SizesType, int32_t>
1139+
? std::numeric_limits<int32_t>::max()
1140+
: std::numeric_limits<uint32_t>::max();
1141+
1142+
std::array<char, kTensorShapeStringSizeLimit> tensor_shape_to_c_string(
1143+
executorch::aten::ArrayRef<executorch::aten::SizesType> shape);
1144+
11231145
/// These APIs should not be used outside of Executor.cpp.
11241146
namespace internal {
11251147
/**

runtime/core/exec_aten/util/test/tensor_util_test.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@
1212
#include <executorch/runtime/platform/runtime.h>
1313
#include <executorch/test/utils/DeathTest.h>
1414
#include <cmath>
15+
#include <cstring>
1516
#include <limits>
1617

1718
using namespace ::testing;
1819
using executorch::aten::ScalarType;
1920
using executorch::aten::Tensor;
2021
using executorch::runtime::extract_scalar_tensor;
22+
using executorch::runtime::kMaximumPrintableTensorShapeElement;
23+
using executorch::runtime::kTensorDimensionLimit;
24+
using executorch::runtime::kTensorShapeStringSizeLimit;
25+
using executorch::runtime::tensor_shape_to_c_string;
2126
using executorch::runtime::testing::TensorFactory;
2227

2328
class TensorUtilTest : public ::testing::Test {
@@ -605,3 +610,36 @@ TEST_F(TensorUtilTest, SameShapesDifferentDimOrder) {
605610
EXPECT_FALSE(tensors_have_same_dim_order(a, c, b));
606611
EXPECT_FALSE(tensors_have_same_dim_order(c, b, a));
607612
}
613+
614+
TEST_F(TensorUtilTest, TensorShapeToCStringBasic) {
615+
std::array<executorch::aten::SizesType, 3> sizes = {123, 456, 789};
616+
auto str = tensor_shape_to_c_string(sizes);
617+
EXPECT_STREQ(str.data(), "(123, 456, 789)");
618+
619+
std::array<executorch::aten::SizesType, 1> one_size = {1234567890};
620+
str = tensor_shape_to_c_string(one_size);
621+
EXPECT_STREQ(str.data(), "(1234567890)");
622+
}
623+
624+
TEST_F(TensorUtilTest, TensorShapeToCStringMaximumLength) {
625+
std::array<
626+
executorch::aten::SizesType,
627+
executorch::runtime::kTensorDimensionLimit>
628+
sizes;
629+
std::fill(
630+
sizes.begin(),
631+
sizes.end(),
632+
executorch::runtime::kMaximumPrintableTensorShapeElement);
633+
634+
auto str = executorch::runtime::tensor_shape_to_c_string(sizes);
635+
636+
std::ostringstream expected;
637+
expected << '(' << kMaximumPrintableTensorShapeElement;
638+
for (int ii = 0; ii < kTensorDimensionLimit - 1; ++ii) {
639+
expected << ", " << kMaximumPrintableTensorShapeElement;
640+
}
641+
expected << ')';
642+
auto expected_str = expected.str();
643+
644+
EXPECT_EQ(expected_str, str.data());
645+
}

0 commit comments

Comments
 (0)