xref: /aosp_15_r20/external/tensorflow/tensorflow/core/kernels/immutable_constant_op_test.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/core/kernels/immutable_constant_op.h"
16 
17 #include <algorithm>
18 #include <tuple>
19 
20 #include "tensorflow/cc/ops/standard_ops.h"
21 #include "tensorflow/core/framework/allocator.h"
22 #include "tensorflow/core/framework/tensor.h"
23 #include "tensorflow/core/graph/graph_def_builder.h"
24 #include "tensorflow/core/lib/core/status_test_util.h"
25 #include "tensorflow/core/lib/io/path.h"
26 #include "tensorflow/core/platform/null_file_system.h"
27 #include "tensorflow/core/platform/test.h"
28 #include "tensorflow/core/platform/test_benchmark.h"
29 #include "tensorflow/core/public/session.h"
30 
31 namespace tensorflow {
32 namespace {
33 // A safe alignment that equal to memmapped page alignment on many modern
34 // architectures.
35 constexpr size_t kTestAlignment = 4096;
36 constexpr size_t kTestTensorSize = 4;
37 constexpr size_t kTestTensorSizeBytes = kTestTensorSize * sizeof(float);
38 
39 // A test ReadOnlyMemoryRegion implementation.
40 class TestReadOnlyMemoryRegion : public ReadOnlyMemoryRegion {
41  public:
42   TestReadOnlyMemoryRegion() = delete;
TestReadOnlyMemoryRegion(uint64 length)43   explicit TestReadOnlyMemoryRegion(uint64 length)
44       : memptr_(cpu_allocator()->AllocateRaw(kTestAlignment, length)),
45         length_(length) {}
~TestReadOnlyMemoryRegion()46   ~TestReadOnlyMemoryRegion() override {
47     cpu_allocator()->DeallocateRaw(memptr_);
48   }
data()49   const void* data() override { return memptr_; }
GetWritableDataStart()50   float* GetWritableDataStart() { return reinterpret_cast<float*>(memptr_); }
length()51   uint64 length() override { return length_; }
52 
53  protected:
54   void* memptr_;
55   uint64 length_;
56 };
57 
58 // A mock file system and environment class that creates ReadOnlyMemoryRegion
59 // from allocated memory.
60 class TestFileSystem : public NullFileSystem {
61  public:
62   ~TestFileSystem() override = default;
63 
64   // import non-transactional method from the base class
65   using NullFileSystem::NewReadOnlyMemoryRegionFromFile;
66 
NewReadOnlyMemoryRegionFromFile(const string & fname,TransactionToken * token,std::unique_ptr<ReadOnlyMemoryRegion> * result)67   Status NewReadOnlyMemoryRegionFromFile(
68       const string& fname, TransactionToken* token,
69       std::unique_ptr<ReadOnlyMemoryRegion>* result) override {
70     float val = 0;
71     StringPiece scheme, host, path;
72     io::ParseURI(fname, &scheme, &host, &path);
73     // For the tests create in-memory regions with float values equal to the
74     // region name.
75     if (path == "/2") {
76       val = 2.0f;
77     } else if (path == "/3") {
78       val = 3.0f;
79     } else {
80       val = 0.0f;
81     }
82 
83     auto region = new TestReadOnlyMemoryRegion(kTestTensorSizeBytes);
84     std::fill_n(region->GetWritableDataStart(), kTestTensorSize, val);
85     result->reset(region);
86     return OkStatus();
87   }
88 };
89 
90 REGISTER_FILE_SYSTEM("test", TestFileSystem);
91 
92 struct ImmutableConstantOpTest {};
93 
TEST(ImmutableConstantOpTest,Simple)94 TEST(ImmutableConstantOpTest, Simple) {
95   const TensorShape kTestTensorShape({4, 1});
96   const TensorShape kTestTensorShapeT({1, 4});
97   auto root = Scope::NewRootScope().ExitOnError();
98   auto node1 =
99       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShape, "test:///2");
100   auto node2 =
101       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShapeT, "test:///3");
102   auto result = ops::MatMul(root, node1, node2);
103   GraphDef graph_def;
104   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
105   SessionOptions session_options;
106   session_options.env = Env::Default();
107   session_options.config.mutable_graph_options()
108       ->mutable_optimizer_options()
109       ->set_opt_level(OptimizerOptions::L0);
110   std::unique_ptr<Session> session(NewSession(session_options));
111   ASSERT_TRUE(session != nullptr) << "Failed to create session";
112   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
113   std::vector<Tensor> outputs;
114   TF_ASSERT_OK(session->Run({}, {result.node()->name() + ":0"}, {}, &outputs));
115   ASSERT_EQ(outputs.size(), 1);
116   EXPECT_EQ(outputs.front().flat<float>()(0), 2.0f * 3.0f);
117   EXPECT_EQ(outputs.front().flat<float>()(1), 2.0f * 3.0f);
118   EXPECT_EQ(outputs.front().flat<float>()(2), 2.0f * 3.0f);
119   EXPECT_EQ(outputs.front().flat<float>()(kTestTensorSize - 1), 2.0f * 3.0f);
120 }
121 
122 // Creates a test graph with two immutable_const tensors and a simple math
123 // operation, one of nodes has wrong size, check that error properly reported.
124 
TEST(ImmutableConstantOpTest,ExecutionError)125 TEST(ImmutableConstantOpTest, ExecutionError) {
126   const TensorShape kBadTensorShape({40, 100});
127   const TensorShape kTestTensorShapeT({1, 4});
128 
129   auto root = Scope::DisabledShapeInferenceScope().ExitOnError();
130   auto node1 =
131       ops::ImmutableConst(root, DT_FLOAT, kBadTensorShape, "test:///2");
132   auto node2 =
133       ops::ImmutableConst(root, DT_FLOAT, kTestTensorShapeT, "test:///3");
134   auto result = ops::MatMul(root, node1, node2);
135   GraphDef graph_def;
136   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
137   SessionOptions session_options;
138   session_options.env = Env::Default();
139   std::unique_ptr<Session> session(NewSession(session_options));
140   ASSERT_TRUE(session != nullptr) << "Failed to create session";
141   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
142   std::vector<Tensor> outputs;
143   // Check that the run returned error.
144   EXPECT_EQ(
145       session->Run({}, {result.node()->name() + ":0"}, {}, &outputs).code(),
146       error::INTERNAL);
147 }
148 
CreateTempFileFloat(Env * env,float value,uint64 size,string * filename)149 Status CreateTempFileFloat(Env* env, float value, uint64 size,
150                            string* filename) {
151   const string dir = testing::TmpDir();
152   *filename = io::JoinPath(dir, strings::StrCat("file_", value));
153   std::unique_ptr<WritableFile> file;
154   TF_RETURN_IF_ERROR(env->NewWritableFile(*filename, &file));
155   for (uint64 i = 0; i < size; ++i) {
156     StringPiece sp(static_cast<char*>(static_cast<void*>(&value)),
157                    sizeof(value));
158     TF_RETURN_IF_ERROR(file->Append(sp));
159   }
160   TF_RETURN_IF_ERROR(file->Close());
161   return OkStatus();
162 }
163 
TEST(ImmutableConstantOpTest,FromFile)164 TEST(ImmutableConstantOpTest, FromFile) {
165   const TensorShape kFileTensorShape({1000, 1});
166   Env* env = Env::Default();
167   auto root = Scope::NewRootScope().ExitOnError();
168 
169   string two_file, three_file;
170   TF_ASSERT_OK(CreateTempFileFloat(env, 2.0f, 1000, &two_file));
171   TF_ASSERT_OK(CreateTempFileFloat(env, 3.0f, 1000, &three_file));
172   auto node1 = ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, two_file);
173   auto node2 =
174       ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, three_file);
175   auto result = ops::MatMul(root, node1, node2, ops::MatMul::TransposeB(true));
176 
177   GraphDef graph_def;
178   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
179   SessionOptions session_options;
180   session_options.config.mutable_graph_options()
181       ->mutable_optimizer_options()
182       ->set_opt_level(OptimizerOptions::L0);
183   std::unique_ptr<Session> session(NewSession(session_options));
184   ASSERT_TRUE(session != nullptr) << "Failed to create session";
185   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
186   std::vector<Tensor> outputs;
187   TF_ASSERT_OK(session->Run({}, {result.node()->name() + ":0"}, {}, &outputs));
188   ASSERT_EQ(outputs.size(), 1);
189   EXPECT_EQ(outputs.front().flat<float>()(0), 2.0f * 3.0f);
190   EXPECT_EQ(outputs.front().flat<float>()(1), 2.0f * 3.0f);
191   EXPECT_EQ(outputs.front().flat<float>()(2), 2.0f * 3.0f);
192 }
193 
CreateTempFileBadString(Env * env,char value,uint64 size,const string suffix,string * filename)194 Status CreateTempFileBadString(Env* env, char value, uint64 size,
195                                const string suffix, string* filename) {
196   const string dir = testing::TmpDir();
197   *filename = io::JoinPath(dir, strings::StrCat("file_", suffix));
198   std::unique_ptr<WritableFile> file;
199   TF_RETURN_IF_ERROR(env->NewWritableFile(*filename, &file));
200   TF_RETURN_IF_ERROR(file->Append(std::string(size, value)));
201   TF_RETURN_IF_ERROR(file->Close());
202   return OkStatus();
203 }
204 
TEST(ImmutableConstantOpTest,FromFileStringUnimplmented)205 TEST(ImmutableConstantOpTest, FromFileStringUnimplmented) {
206   const TensorShape kFileTensorShape({1});
207   Env* env = Env::Default();
208   auto root = Scope::NewRootScope().ExitOnError();
209 
210   string bad_file;
211   TF_ASSERT_OK(CreateTempFileBadString(env, '\xe2', 128, "bad_e2", &bad_file));
212   auto result =
213       ops::ImmutableConst(root, DT_STRING, kFileTensorShape, bad_file);
214   GraphDef graph_def;
215   TF_ASSERT_OK(root.ToGraphDef(&graph_def));
216   SessionOptions session_options;
217   session_options.env = Env::Default();
218   std::unique_ptr<Session> session(NewSession(session_options));
219   ASSERT_TRUE(session != nullptr) << "Failed to create session";
220   TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
221   std::vector<Tensor> outputs;
222   // Check that the run returned error.
223   EXPECT_EQ(
224       session->Run({}, {result.node()->name() + ":0"}, {}, &outputs).code(),
225       error::UNIMPLEMENTED);
226 }
227 
228 }  // namespace
229 }  // namespace tensorflow
230