• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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