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 Status::OK();
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
CreateTempFile(Env * env,float value,uint64 size,string * filename)149 Status CreateTempFile(Env* env, float value, uint64 size, string* filename) {
150 const string dir = testing::TmpDir();
151 *filename = io::JoinPath(dir, strings::StrCat("file_", value));
152 std::unique_ptr<WritableFile> file;
153 TF_RETURN_IF_ERROR(env->NewWritableFile(*filename, &file));
154 for (uint64 i = 0; i < size; ++i) {
155 StringPiece sp(static_cast<char*>(static_cast<void*>(&value)),
156 sizeof(value));
157 TF_RETURN_IF_ERROR(file->Append(sp));
158 }
159 TF_RETURN_IF_ERROR(file->Close());
160 return Status::OK();
161 }
162
TEST(ImmutableConstantOpTest,FromFile)163 TEST(ImmutableConstantOpTest, FromFile) {
164 const TensorShape kFileTensorShape({1000, 1});
165 Env* env = Env::Default();
166 auto root = Scope::NewRootScope().ExitOnError();
167
168 string two_file, three_file;
169 TF_ASSERT_OK(CreateTempFile(env, 2.0f, 1000, &two_file));
170 TF_ASSERT_OK(CreateTempFile(env, 3.0f, 1000, &three_file));
171 auto node1 = ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, two_file);
172 auto node2 =
173 ops::ImmutableConst(root, DT_FLOAT, kFileTensorShape, three_file);
174 auto result = ops::MatMul(root, node1, node2, ops::MatMul::TransposeB(true));
175
176 GraphDef graph_def;
177 TF_ASSERT_OK(root.ToGraphDef(&graph_def));
178 SessionOptions session_options;
179 session_options.config.mutable_graph_options()
180 ->mutable_optimizer_options()
181 ->set_opt_level(OptimizerOptions::L0);
182 std::unique_ptr<Session> session(NewSession(session_options));
183 ASSERT_TRUE(session != nullptr) << "Failed to create session";
184 TF_ASSERT_OK(session->Create(graph_def)) << "Can't create test graph";
185 std::vector<Tensor> outputs;
186 TF_ASSERT_OK(session->Run({}, {result.node()->name() + ":0"}, {}, &outputs));
187 ASSERT_EQ(outputs.size(), 1);
188 EXPECT_EQ(outputs.front().flat<float>()(0), 2.0f * 3.0f);
189 EXPECT_EQ(outputs.front().flat<float>()(1), 2.0f * 3.0f);
190 EXPECT_EQ(outputs.front().flat<float>()(2), 2.0f * 3.0f);
191 }
192
193 } // namespace
194 } // namespace tensorflow
195