TensorFlow Serving C++ API Documentation
fast_read_dynamic_ptr_test.cc
1 /* Copyright 2016 Google Inc. 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 
16 #include "tensorflow_serving/util/fast_read_dynamic_ptr.h"
17 
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
22 #include <gtest/gtest.h>
23 #include "tensorflow/core/platform/env.h"
24 
25 namespace tensorflow {
26 namespace serving {
27 namespace {
28 
29 template <typename T>
30 class FastReadDynamicPtrTest : public ::testing::Test {};
31 
32 using FastReadDynamicPtrTypes = ::testing::Types<
33  FastReadDynamicPtr<int>,
34  FastReadDynamicPtr<int, internal_read_ptr_holder::ShardedReadPtrs<int>>,
35  FastReadDynamicPtr<int, internal_read_ptr_holder::SingleReadPtr<int>>>;
36 
37 TYPED_TEST_SUITE(FastReadDynamicPtrTest, FastReadDynamicPtrTypes);
38 
39 TYPED_TEST(FastReadDynamicPtrTest, SingleThreaded) {
40  TypeParam fast_read_int;
41 
42  {
43  // Initially the object should be null.
44  std::shared_ptr<const int> pointer = fast_read_int.get();
45  EXPECT_EQ(pointer, nullptr);
46  }
47 
48  // Swap in an actual value.
49  std::unique_ptr<int> i(new int(1));
50  fast_read_int.Update(std::move(i));
51  EXPECT_EQ(nullptr, i);
52 
53  {
54  std::shared_ptr<const int> pointer = fast_read_int.get();
55  EXPECT_EQ(*pointer, 1);
56  }
57 }
58 
59 TYPED_TEST(FastReadDynamicPtrTest, MultiThreaded) {
60  const int kNumThreads = 4;
61 
62  TypeParam fast_read_int;
63 
64  {
65  std::unique_ptr<int> tmp(new int(0));
66  EXPECT_EQ(nullptr, fast_read_int.Update(std::move(tmp)));
67  }
68 
69  std::vector<std::unique_ptr<Thread>> threads;
70  for (int thread_index = 0; thread_index < kNumThreads; ++thread_index) {
71  // Spawn a new thread.
72  threads.emplace_back(Env::Default()->StartThread(
73  {}, "Increment", [thread_index, &fast_read_int]() {
74  const int kMaxValue = 1000;
75  int last_value = -1;
76  // Loops until 'fast_read_int' becomes 'max_value'.
77  for (;;) {
78  int value = -1;
79  {
80  std::shared_ptr<const int> pointer = fast_read_int.get();
81  value = *pointer;
82  }
83 
84  EXPECT_GE(value, last_value);
85  if (value == kMaxValue) {
86  return;
87  }
88  if (value % kNumThreads == thread_index) {
89  std::unique_ptr<int> tmp(new int(value + 1));
90  fast_read_int.Update(std::move(tmp));
91  }
92  }
93  }));
94  }
95 }
96 
97 TYPED_TEST(FastReadDynamicPtrTest, WaitsForReadPtrsBeforeDestruction) {
98  const int expected = 12;
99  std::unique_ptr<TypeParam> fast_read_int(new TypeParam);
100  fast_read_int->Update(std::unique_ptr<int>(new int(expected)));
101  Notification got;
102  std::unique_ptr<Thread> thread(Env::Default()->StartThread({}, "Holder", [&] {
103  auto p = fast_read_int->get();
104  ASSERT_NE(p, nullptr);
105  EXPECT_EQ(expected, *p);
106  got.Notify();
107  // The other thread can't notify us that they deleted
108  // fast_read_int because that destruction will block until
109  // we're done with p. We sleep so that with high
110  // probability, deletion was attempted.
111  Env::Default()->SleepForMicroseconds(1e7);
112  EXPECT_EQ(expected, *p);
113  }));
114  got.WaitForNotification();
115  // Destruction must block until all outstanding ReadPtrs are destroyed.
116  fast_read_int = nullptr;
117 }
118 
119 } // namespace
120 } // namespace serving
121 } // namespace tensorflow