1 /* Copyright 2017 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
16 // Unit tests for StatusOr
17
18 #include "tensorflow/core/platform/statusor.h"
19
20 #include <memory>
21 #include <type_traits>
22 #include <utility>
23
24 #include "tensorflow/core/lib/core/errors.h"
25 #include "tensorflow/core/platform/macros.h"
26 #include "tensorflow/core/platform/test.h"
27 #include "tensorflow/core/platform/test_benchmark.h"
28
29 namespace tensorflow {
30 namespace {
31
32 class Base1 {
33 public:
~Base1()34 virtual ~Base1() {}
35 int pad_;
36 };
37
38 class Base2 {
39 public:
~Base2()40 virtual ~Base2() {}
41 int yetotherpad_;
42 };
43
44 class Derived : public Base1, public Base2 {
45 public:
~Derived()46 ~Derived() override {}
47 int evenmorepad_;
48 };
49
50 class CopyNoAssign {
51 public:
CopyNoAssign(int value)52 explicit CopyNoAssign(int value) : foo_(value) {}
CopyNoAssign(const CopyNoAssign & other)53 CopyNoAssign(const CopyNoAssign& other) : foo_(other.foo_) {}
54 int foo_;
55
56 private:
57 const CopyNoAssign& operator=(const CopyNoAssign&);
58 };
59
60 class NoDefaultConstructor {
61 public:
62 explicit NoDefaultConstructor(int foo);
63 };
64
65 static_assert(!std::is_default_constructible<NoDefaultConstructor>(),
66 "Should not be default-constructible.");
67
ReturnUniquePtr()68 StatusOr<std::unique_ptr<int>> ReturnUniquePtr() {
69 // Uses implicit constructor from T&&
70 return std::unique_ptr<int>(new int(0));
71 }
72
TEST(StatusOr,ElementType)73 TEST(StatusOr, ElementType) {
74 static_assert(std::is_same<StatusOr<int>::element_type, int>(), "");
75 static_assert(std::is_same<StatusOr<char>::element_type, char>(), "");
76 }
77
TEST(StatusOr,NullPointerStatusOr)78 TEST(StatusOr, NullPointerStatusOr) {
79 // As a very special case, null-plain-pointer StatusOr used to be an
80 // error. Test that it no longer is.
81 StatusOr<int*> null_status(nullptr);
82 EXPECT_TRUE(null_status.ok());
83 EXPECT_EQ(null_status.ValueOrDie(), nullptr);
84 }
85
TEST(StatusOr,TestNoDefaultConstructorInitialization)86 TEST(StatusOr, TestNoDefaultConstructorInitialization) {
87 // Explicitly initialize it with an error code.
88 StatusOr<NoDefaultConstructor> statusor(tensorflow::errors::Cancelled(""));
89 EXPECT_FALSE(statusor.ok());
90 EXPECT_EQ(statusor.status().code(), tensorflow::error::CANCELLED);
91
92 // Default construction of StatusOr initializes it with an UNKNOWN error code.
93 StatusOr<NoDefaultConstructor> statusor2;
94 EXPECT_FALSE(statusor2.ok());
95 EXPECT_EQ(statusor2.status().code(), tensorflow::error::UNKNOWN);
96 }
97
TEST(StatusOr,TestMoveOnlyInitialization)98 TEST(StatusOr, TestMoveOnlyInitialization) {
99 StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
100 ASSERT_TRUE(thing.ok());
101 EXPECT_EQ(0, *thing.ValueOrDie());
102 int* previous = thing.ValueOrDie().get();
103
104 thing = ReturnUniquePtr();
105 EXPECT_TRUE(thing.ok());
106 EXPECT_EQ(0, *thing.ValueOrDie());
107 EXPECT_NE(previous, thing.ValueOrDie().get());
108 }
109
TEST(StatusOr,TestMoveOnlyStatusCtr)110 TEST(StatusOr, TestMoveOnlyStatusCtr) {
111 StatusOr<std::unique_ptr<int>> thing(tensorflow::errors::Cancelled(""));
112 ASSERT_FALSE(thing.ok());
113 }
114
TEST(StatusOr,TestMoveOnlyValueExtraction)115 TEST(StatusOr, TestMoveOnlyValueExtraction) {
116 StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
117 ASSERT_TRUE(thing.ok());
118 std::unique_ptr<int> ptr = std::move(thing).value();
119 EXPECT_EQ(0, *ptr);
120
121 thing = std::move(ptr);
122 ptr = std::move(thing.ValueOrDie());
123 EXPECT_EQ(0, *ptr);
124 }
125
TEST(StatusOr,TestMoveOnlyConversion)126 TEST(StatusOr, TestMoveOnlyConversion) {
127 StatusOr<std::unique_ptr<const int>> const_thing(ReturnUniquePtr());
128 EXPECT_TRUE(const_thing.ok());
129 EXPECT_EQ(0, *const_thing.ValueOrDie());
130
131 // Test rvalue converting assignment
132 const int* const_previous = const_thing.ValueOrDie().get();
133 const_thing = ReturnUniquePtr();
134 EXPECT_TRUE(const_thing.ok());
135 EXPECT_EQ(0, *const_thing.ValueOrDie());
136 EXPECT_NE(const_previous, const_thing.ValueOrDie().get());
137 }
138
TEST(StatusOr,TestMoveOnlyVector)139 TEST(StatusOr, TestMoveOnlyVector) {
140 // Sanity check that StatusOr<MoveOnly> works in vector.
141 std::vector<StatusOr<std::unique_ptr<int>>> vec;
142 vec.push_back(ReturnUniquePtr());
143 vec.resize(2);
144 auto another_vec = std::move(vec);
145 EXPECT_EQ(0, *another_vec[0].ValueOrDie());
146 EXPECT_EQ(tensorflow::error::UNKNOWN, another_vec[1].status().code());
147 }
148
TEST(StatusOr,TestMoveWithValuesAndErrors)149 TEST(StatusOr, TestMoveWithValuesAndErrors) {
150 StatusOr<std::string> status_or(std::string(1000, '0'));
151 StatusOr<std::string> value1(std::string(1000, '1'));
152 StatusOr<std::string> value2(std::string(1000, '2'));
153 StatusOr<std::string> error1(Status(tensorflow::error::UNKNOWN, "error1"));
154 StatusOr<std::string> error2(Status(tensorflow::error::UNKNOWN, "error2"));
155
156 ASSERT_TRUE(status_or.ok());
157 EXPECT_EQ(std::string(1000, '0'), status_or.ValueOrDie());
158
159 // Overwrite the value in status_or with another value.
160 status_or = std::move(value1);
161 ASSERT_TRUE(status_or.ok());
162 EXPECT_EQ(std::string(1000, '1'), status_or.ValueOrDie());
163
164 // Overwrite the value in status_or with an error.
165 status_or = std::move(error1);
166 ASSERT_FALSE(status_or.ok());
167 EXPECT_EQ("error1", status_or.status().error_message());
168
169 // Overwrite the error in status_or with another error.
170 status_or = std::move(error2);
171 ASSERT_FALSE(status_or.ok());
172 EXPECT_EQ("error2", status_or.status().error_message());
173
174 // Overwrite the error with a value.
175 status_or = std::move(value2);
176 ASSERT_TRUE(status_or.ok());
177 EXPECT_EQ(std::string(1000, '2'), status_or.ValueOrDie());
178 }
179
TEST(StatusOr,TestCopyWithValuesAndErrors)180 TEST(StatusOr, TestCopyWithValuesAndErrors) {
181 StatusOr<std::string> status_or(std::string(1000, '0'));
182 StatusOr<std::string> value1(std::string(1000, '1'));
183 StatusOr<std::string> value2(std::string(1000, '2'));
184 StatusOr<std::string> error1(Status(tensorflow::error::UNKNOWN, "error1"));
185 StatusOr<std::string> error2(Status(tensorflow::error::UNKNOWN, "error2"));
186
187 ASSERT_TRUE(status_or.ok());
188 EXPECT_EQ(std::string(1000, '0'), status_or.ValueOrDie());
189
190 // Overwrite the value in status_or with another value.
191 status_or = value1;
192 ASSERT_TRUE(status_or.ok());
193 EXPECT_EQ(std::string(1000, '1'), status_or.ValueOrDie());
194
195 // Overwrite the value in status_or with an error.
196 status_or = error1;
197 ASSERT_FALSE(status_or.ok());
198 EXPECT_EQ("error1", status_or.status().error_message());
199
200 // Overwrite the error in status_or with another error.
201 status_or = error2;
202 ASSERT_FALSE(status_or.ok());
203 EXPECT_EQ("error2", status_or.status().error_message());
204
205 // Overwrite the error with a value.
206 status_or = value2;
207 ASSERT_TRUE(status_or.ok());
208 EXPECT_EQ(std::string(1000, '2'), status_or.ValueOrDie());
209
210 // Verify original values unchanged.
211 EXPECT_EQ(std::string(1000, '1'), value1.ValueOrDie());
212 EXPECT_EQ("error1", error1.status().error_message());
213 EXPECT_EQ("error2", error2.status().error_message());
214 EXPECT_EQ(std::string(1000, '2'), value2.ValueOrDie());
215 }
216
TEST(StatusOr,TestDefaultCtor)217 TEST(StatusOr, TestDefaultCtor) {
218 StatusOr<int> thing;
219 EXPECT_FALSE(thing.ok());
220 EXPECT_EQ(thing.status().code(), tensorflow::error::UNKNOWN);
221 }
222
TEST(StatusOrDeathTest,TestDefaultCtorValue)223 TEST(StatusOrDeathTest, TestDefaultCtorValue) {
224 StatusOr<int> thing;
225 EXPECT_DEATH(thing.ValueOrDie(), "");
226
227 const StatusOr<int> thing2;
228 EXPECT_DEATH(thing.ValueOrDie(), "");
229 }
230
TEST(StatusOr,TestStatusCtor)231 TEST(StatusOr, TestStatusCtor) {
232 StatusOr<int> thing(Status(tensorflow::error::CANCELLED, ""));
233 EXPECT_FALSE(thing.ok());
234 EXPECT_EQ(thing.status().code(), tensorflow::error::CANCELLED);
235 }
236
TEST(StatusOr,TestValueCtor)237 TEST(StatusOr, TestValueCtor) {
238 const int kI = 4;
239 const StatusOr<int> thing(kI);
240 EXPECT_TRUE(thing.ok());
241 EXPECT_EQ(kI, thing.ValueOrDie());
242 }
243
TEST(StatusOr,TestCopyCtorStatusOk)244 TEST(StatusOr, TestCopyCtorStatusOk) {
245 const int kI = 4;
246 const StatusOr<int> original(kI);
247 const StatusOr<int> copy(original);
248 EXPECT_EQ(copy.status(), original.status());
249 EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
250 }
251
TEST(StatusOr,TestCopyCtorStatusNotOk)252 TEST(StatusOr, TestCopyCtorStatusNotOk) {
253 StatusOr<int> original(Status(tensorflow::error::CANCELLED, ""));
254 StatusOr<int> copy(original);
255 EXPECT_EQ(copy.status(), original.status());
256 }
257
TEST(StatusOr,TestCopyCtorNonAssignable)258 TEST(StatusOr, TestCopyCtorNonAssignable) {
259 const int kI = 4;
260 CopyNoAssign value(kI);
261 StatusOr<CopyNoAssign> original(value);
262 StatusOr<CopyNoAssign> copy(original);
263 EXPECT_EQ(copy.status(), original.status());
264 EXPECT_EQ(original.ValueOrDie().foo_, copy.ValueOrDie().foo_);
265 }
266
TEST(StatusOr,TestCopyCtorStatusOKConverting)267 TEST(StatusOr, TestCopyCtorStatusOKConverting) {
268 const int kI = 4;
269 StatusOr<int> original(kI);
270 StatusOr<double> copy(original);
271 EXPECT_EQ(copy.status(), original.status());
272 EXPECT_DOUBLE_EQ(original.ValueOrDie(), copy.ValueOrDie());
273 }
274
TEST(StatusOr,TestCopyCtorStatusNotOkConverting)275 TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
276 StatusOr<int> original(Status(tensorflow::error::CANCELLED, ""));
277 StatusOr<double> copy(original);
278 EXPECT_EQ(copy.status(), original.status());
279 }
280
TEST(StatusOr,TestAssignmentStatusOk)281 TEST(StatusOr, TestAssignmentStatusOk) {
282 const int kI = 4;
283 StatusOr<int> source(kI);
284 StatusOr<int> target;
285 target = source;
286 EXPECT_EQ(target.status(), source.status());
287 EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
288 }
289
TEST(StatusOr,TestAssignmentStatusNotOk)290 TEST(StatusOr, TestAssignmentStatusNotOk) {
291 StatusOr<int> source(Status(tensorflow::error::CANCELLED, ""));
292 StatusOr<int> target;
293 target = source;
294 EXPECT_EQ(target.status(), source.status());
295 }
296
TEST(StatusOr,TestStatus)297 TEST(StatusOr, TestStatus) {
298 StatusOr<int> good(4);
299 EXPECT_TRUE(good.ok());
300 StatusOr<int> bad(Status(tensorflow::error::CANCELLED, ""));
301 EXPECT_FALSE(bad.ok());
302 EXPECT_EQ(bad.status(), Status(tensorflow::error::CANCELLED, ""));
303 }
304
TEST(StatusOr,TestValue)305 TEST(StatusOr, TestValue) {
306 const int kI = 4;
307 StatusOr<int> thing(kI);
308 EXPECT_EQ(kI, thing.ValueOrDie());
309 }
310
TEST(StatusOr,TestValueConst)311 TEST(StatusOr, TestValueConst) {
312 const int kI = 4;
313 const StatusOr<int> thing(kI);
314 EXPECT_EQ(kI, thing.ValueOrDie());
315 }
316
TEST(StatusOrDeathTest,TestValueNotOk)317 TEST(StatusOrDeathTest, TestValueNotOk) {
318 StatusOr<int> thing(Status(tensorflow::error::CANCELLED, "cancelled"));
319 EXPECT_DEATH(thing.ValueOrDie(), "cancelled");
320 }
321
TEST(StatusOrDeathTest,TestValueNotOkConst)322 TEST(StatusOrDeathTest, TestValueNotOkConst) {
323 const StatusOr<int> thing(Status(tensorflow::error::UNKNOWN, ""));
324 EXPECT_DEATH(thing.ValueOrDie(), "");
325 }
326
TEST(StatusOr,TestPointerDefaultCtor)327 TEST(StatusOr, TestPointerDefaultCtor) {
328 StatusOr<int*> thing;
329 EXPECT_FALSE(thing.ok());
330 EXPECT_EQ(thing.status().code(), tensorflow::error::UNKNOWN);
331 }
332
TEST(StatusOrDeathTest,TestPointerDefaultCtorValue)333 TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) {
334 StatusOr<int*> thing;
335 EXPECT_DEATH(thing.ValueOrDie(), "");
336 }
337
TEST(StatusOr,TestPointerStatusCtor)338 TEST(StatusOr, TestPointerStatusCtor) {
339 StatusOr<int*> thing(Status(tensorflow::error::CANCELLED, ""));
340 EXPECT_FALSE(thing.ok());
341 EXPECT_EQ(thing.status(), Status(tensorflow::error::CANCELLED, ""));
342 }
343
TEST(StatusOr,TestPointerValueCtor)344 TEST(StatusOr, TestPointerValueCtor) {
345 const int kI = 4;
346 StatusOr<const int*> thing(&kI);
347 EXPECT_TRUE(thing.ok());
348 EXPECT_EQ(&kI, thing.ValueOrDie());
349 }
350
TEST(StatusOr,TestPointerCopyCtorStatusOk)351 TEST(StatusOr, TestPointerCopyCtorStatusOk) {
352 const int kI = 0;
353 StatusOr<const int*> original(&kI);
354 StatusOr<const int*> copy(original);
355 EXPECT_EQ(copy.status(), original.status());
356 EXPECT_EQ(original.ValueOrDie(), copy.ValueOrDie());
357 }
358
TEST(StatusOr,TestPointerCopyCtorStatusNotOk)359 TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
360 StatusOr<int*> original(Status(tensorflow::error::CANCELLED, ""));
361 StatusOr<int*> copy(original);
362 EXPECT_EQ(copy.status(), original.status());
363 }
364
TEST(StatusOr,TestPointerCopyCtorStatusOKConverting)365 TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
366 Derived derived;
367 StatusOr<Derived*> original(&derived);
368 StatusOr<Base2*> copy(original);
369 EXPECT_EQ(copy.status(), original.status());
370 EXPECT_EQ(static_cast<const Base2*>(original.ValueOrDie()),
371 copy.ValueOrDie());
372 }
373
TEST(StatusOr,TestPointerCopyCtorStatusNotOkConverting)374 TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
375 StatusOr<Derived*> original(Status(tensorflow::error::CANCELLED, ""));
376 StatusOr<Base2*> copy(original);
377 EXPECT_EQ(copy.status(), original.status());
378 }
379
TEST(StatusOr,TestPointerAssignmentStatusOk)380 TEST(StatusOr, TestPointerAssignmentStatusOk) {
381 const int kI = 0;
382 StatusOr<const int*> source(&kI);
383 StatusOr<const int*> target;
384 target = source;
385 EXPECT_EQ(target.status(), source.status());
386 EXPECT_EQ(source.ValueOrDie(), target.ValueOrDie());
387 }
388
TEST(StatusOr,TestPointerAssignmentStatusNotOk)389 TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
390 StatusOr<int*> source(Status(tensorflow::error::CANCELLED, ""));
391 StatusOr<int*> target;
392 target = source;
393 EXPECT_EQ(target.status(), source.status());
394 }
395
TEST(StatusOr,TestPointerStatus)396 TEST(StatusOr, TestPointerStatus) {
397 const int kI = 0;
398 StatusOr<const int*> good(&kI);
399 EXPECT_TRUE(good.ok());
400 StatusOr<const int*> bad(Status(tensorflow::error::CANCELLED, ""));
401 EXPECT_EQ(bad.status(), Status(tensorflow::error::CANCELLED, ""));
402 }
403
TEST(StatusOr,TestPointerValue)404 TEST(StatusOr, TestPointerValue) {
405 const int kI = 0;
406 StatusOr<const int*> thing(&kI);
407 EXPECT_EQ(&kI, thing.ValueOrDie());
408 }
409
TEST(StatusOr,TestPointerValueConst)410 TEST(StatusOr, TestPointerValueConst) {
411 const int kI = 0;
412 const StatusOr<const int*> thing(&kI);
413 EXPECT_EQ(&kI, thing.ValueOrDie());
414 }
415
TEST(StatusOr,TestArrowOperator)416 TEST(StatusOr, TestArrowOperator) {
417 StatusOr<std::unique_ptr<int>> uptr = ReturnUniquePtr();
418 EXPECT_EQ(*uptr->get(), 0);
419 }
420
TEST(StatusOr,TestArrowOperatorNotOk)421 TEST(StatusOr, TestArrowOperatorNotOk) {
422 StatusOr<Base1> error(Status(tensorflow::error::CANCELLED, "cancelled"));
423 EXPECT_DEATH(error->pad_++, "cancelled");
424 }
425
TEST(StatusOr,TestStarOperator)426 TEST(StatusOr, TestStarOperator) {
427 StatusOr<std::unique_ptr<int>> uptr = ReturnUniquePtr();
428 EXPECT_EQ(**uptr, 0);
429 }
430
TEST(StatusOr,TestStarOperatorDeath)431 TEST(StatusOr, TestStarOperatorDeath) {
432 StatusOr<Base1> error(Status(tensorflow::error::CANCELLED, "cancelled"));
433 EXPECT_DEATH(*error, "cancelled");
434 }
435
436 // NOTE(tucker): StatusOr does not support this kind
437 // of resize op.
438 // TEST(StatusOr, StatusOrVectorOfUniquePointerCanResize) {
439 // using EvilType = std::vector<std::unique_ptr<int>>;
440 // static_assert(std::is_copy_constructible<EvilType>::value, "");
441 // std::vector<StatusOr<EvilType>> v(5);
442 // v.reserve(v.capacity() + 10);
443 // }
444
TEST(StatusOrDeathTest,TestPointerValueNotOk)445 TEST(StatusOrDeathTest, TestPointerValueNotOk) {
446 StatusOr<int*> thing(Status(tensorflow::error::CANCELLED, "cancelled"));
447 EXPECT_DEATH(thing.ValueOrDie(), "cancelled");
448 }
449
TEST(StatusOrDeathTest,TestPointerValueNotOkConst)450 TEST(StatusOrDeathTest, TestPointerValueNotOkConst) {
451 const StatusOr<int*> thing(Status(tensorflow::error::CANCELLED, "cancelled"));
452 EXPECT_DEATH(thing.ValueOrDie(), "cancelled");
453 }
454
MakeStatus()455 static StatusOr<int> MakeStatus() { return 100; }
456 // A factory to help us benchmark the various factory styles. All of
457 // the factory methods are marked as non-inlineable so as to more
458 // accurately simulate calling a factory for which you do not have
459 // visibility of implementation. Similarly, the value_ variable is
460 // marked volatile to prevent the compiler from getting too clever
461 // about detecting that the same value is used in all loop iterations.
462 template <typename T>
463 class BenchmarkFactory {
464 public:
465 // Construct a new factory. Allocate an object which will always
466 // be the result of the factory methods.
BenchmarkFactory()467 BenchmarkFactory() : value_(new T) {}
468
469 // Destroy this factory, including the result value.
~BenchmarkFactory()470 ~BenchmarkFactory() { delete value_; }
471
472 // A trivial factory that just returns the value. There is no status
473 // object that could be returned to encapsulate an error
TrivialFactory()474 T* TrivialFactory() TF_ATTRIBUTE_NOINLINE { return value_; }
475
476 // A more sophisticated factory, which returns a status to indicate
477 // the result of the operation. The factory result is populated into
478 // the user provided pointer result.
ArgumentFactory(T ** result)479 Status ArgumentFactory(T** result) TF_ATTRIBUTE_NOINLINE {
480 *result = value_;
481 return OkStatus();
482 }
483
ArgumentFactoryFail(T ** result)484 Status ArgumentFactoryFail(T** result) TF_ATTRIBUTE_NOINLINE {
485 *result = nullptr;
486 return Status(tensorflow::error::CANCELLED, "");
487 }
488
ArgumentFactoryFailShortMsg(T ** result)489 Status ArgumentFactoryFailShortMsg(T** result) TF_ATTRIBUTE_NOINLINE {
490 *result = nullptr;
491 return Status(::tensorflow::error::INTERNAL, "");
492 }
493
ArgumentFactoryFailLongMsg(T ** result)494 Status ArgumentFactoryFailLongMsg(T** result) TF_ATTRIBUTE_NOINLINE {
495 *result = nullptr;
496 return Status(::tensorflow::error::INTERNAL,
497 "a big string of message junk that will never be read");
498 }
499
500 // A factory that returns a StatusOr<T*>. If the factory operation
501 // is OK, then the StatusOr<T*> will hold a T*. Otherwise, it will
502 // hold a status explaining the error.
StatusOrFactory()503 StatusOr<T*> StatusOrFactory() TF_ATTRIBUTE_NOINLINE {
504 return static_cast<T*>(value_);
505 }
506
StatusOrFactoryFail()507 StatusOr<T*> StatusOrFactoryFail() TF_ATTRIBUTE_NOINLINE {
508 return Status(tensorflow::error::CANCELLED, "");
509 }
510
StatusOrFactoryFailShortMsg()511 StatusOr<T*> StatusOrFactoryFailShortMsg() TF_ATTRIBUTE_NOINLINE {
512 return Status(::tensorflow::error::INTERNAL, "");
513 }
514
StatusOrFactoryFailLongMsg()515 StatusOr<T*> StatusOrFactoryFailLongMsg() TF_ATTRIBUTE_NOINLINE {
516 return Status(::tensorflow::error::INTERNAL,
517 "a big string of message junk that will never be read");
518 }
519
520 private:
521 T* volatile value_;
522 TF_DISALLOW_COPY_AND_ASSIGN(BenchmarkFactory);
523 };
524
525 // A simple type we use with the factory.
526 class BenchmarkType {
527 public:
BenchmarkType()528 BenchmarkType() {}
~BenchmarkType()529 virtual ~BenchmarkType() {}
DoWork()530 virtual void DoWork() TF_ATTRIBUTE_NOINLINE {}
531
532 private:
533 TF_DISALLOW_COPY_AND_ASSIGN(BenchmarkType);
534 };
535
536 // Calibrate the amount of time spent just calling DoWork, since each of our
537 // tests will do this, we can subtract this out of benchmark results.
BM_CalibrateWorkLoop(::testing::benchmark::State & state)538 void BM_CalibrateWorkLoop(::testing::benchmark::State& state) {
539 BenchmarkFactory<BenchmarkType> factory;
540 BenchmarkType* result = factory.TrivialFactory();
541 for (auto s : state) {
542 if (result != nullptr) {
543 result->DoWork();
544 }
545 }
546 }
547 BENCHMARK(BM_CalibrateWorkLoop);
548
549 // Measure the time taken to call into the factory, return the value,
550 // determine that it is OK, and invoke a trivial function.
BM_TrivialFactory(::testing::benchmark::State & state)551 void BM_TrivialFactory(::testing::benchmark::State& state) {
552 BenchmarkFactory<BenchmarkType> factory;
553 for (auto s : state) {
554 BenchmarkType* result = factory.TrivialFactory();
555 if (result != nullptr) {
556 result->DoWork();
557 }
558 }
559 }
560 BENCHMARK(BM_TrivialFactory);
561
562 // Measure the time taken to call into the factory, providing an
563 // out-param for the result, evaluating the status result and the
564 // result pointer, and invoking the trivial function.
BM_ArgumentFactory(::testing::benchmark::State & state)565 void BM_ArgumentFactory(::testing::benchmark::State& state) {
566 BenchmarkFactory<BenchmarkType> factory;
567 for (auto s : state) {
568 BenchmarkType* result = nullptr;
569 Status status = factory.ArgumentFactory(&result);
570 if (status.ok() && result != nullptr) {
571 result->DoWork();
572 }
573 }
574 }
575 BENCHMARK(BM_ArgumentFactory);
576
577 // Measure the time to use the StatusOr<T*> factory, evaluate the result,
578 // and invoke the trivial function.
BM_StatusOrFactory(::testing::benchmark::State & state)579 void BM_StatusOrFactory(::testing::benchmark::State& state) {
580 BenchmarkFactory<BenchmarkType> factory;
581 for (auto s : state) {
582 StatusOr<BenchmarkType*> result = factory.StatusOrFactory();
583 if (result.ok()) {
584 result.ValueOrDie()->DoWork();
585 }
586 }
587 }
588 BENCHMARK(BM_StatusOrFactory);
589
590 // Measure the time taken to call into the factory, providing an
591 // out-param for the result, evaluating the status result and the
592 // result pointer, and invoking the trivial function.
BM_ArgumentFactoryFail(::testing::benchmark::State & state)593 void BM_ArgumentFactoryFail(::testing::benchmark::State& state) {
594 BenchmarkFactory<BenchmarkType> factory;
595 for (auto s : state) {
596 BenchmarkType* result = nullptr;
597 Status status = factory.ArgumentFactoryFail(&result);
598 if (status.ok() && result != nullptr) {
599 result->DoWork();
600 }
601 }
602 }
603 BENCHMARK(BM_ArgumentFactoryFail);
604
605 // Measure the time to use the StatusOr<T*> factory, evaluate the result,
606 // and invoke the trivial function.
BM_StatusOrFactoryFail(::testing::benchmark::State & state)607 void BM_StatusOrFactoryFail(::testing::benchmark::State& state) {
608 BenchmarkFactory<BenchmarkType> factory;
609 for (auto s : state) {
610 StatusOr<BenchmarkType*> result = factory.StatusOrFactoryFail();
611 if (result.ok()) {
612 result.ValueOrDie()->DoWork();
613 }
614 }
615 }
616 BENCHMARK(BM_StatusOrFactoryFail);
617
618 // Measure the time taken to call into the factory, providing an
619 // out-param for the result, evaluating the status result and the
620 // result pointer, and invoking the trivial function.
BM_ArgumentFactoryFailShortMsg(::testing::benchmark::State & state)621 void BM_ArgumentFactoryFailShortMsg(::testing::benchmark::State& state) {
622 BenchmarkFactory<BenchmarkType> factory;
623 for (auto s : state) {
624 BenchmarkType* result = nullptr;
625 Status status = factory.ArgumentFactoryFailShortMsg(&result);
626 if (status.ok() && result != nullptr) {
627 result->DoWork();
628 }
629 }
630 }
631 BENCHMARK(BM_ArgumentFactoryFailShortMsg);
632
633 // Measure the time to use the StatusOr<T*> factory, evaluate the result,
634 // and invoke the trivial function.
BM_StatusOrFactoryFailShortMsg(::testing::benchmark::State & state)635 void BM_StatusOrFactoryFailShortMsg(::testing::benchmark::State& state) {
636 BenchmarkFactory<BenchmarkType> factory;
637 for (auto s : state) {
638 StatusOr<BenchmarkType*> result = factory.StatusOrFactoryFailShortMsg();
639 if (result.ok()) {
640 result.ValueOrDie()->DoWork();
641 }
642 }
643 }
644 BENCHMARK(BM_StatusOrFactoryFailShortMsg);
645
646 // Measure the time taken to call into the factory, providing an
647 // out-param for the result, evaluating the status result and the
648 // result pointer, and invoking the trivial function.
BM_ArgumentFactoryFailLongMsg(::testing::benchmark::State & state)649 void BM_ArgumentFactoryFailLongMsg(::testing::benchmark::State& state) {
650 BenchmarkFactory<BenchmarkType> factory;
651 for (auto s : state) {
652 BenchmarkType* result = nullptr;
653 Status status = factory.ArgumentFactoryFailLongMsg(&result);
654 if (status.ok() && result != nullptr) {
655 result->DoWork();
656 }
657 }
658 }
659 BENCHMARK(BM_ArgumentFactoryFailLongMsg);
660
661 // Measure the time to use the StatusOr<T*> factory, evaluate the result,
662 // and invoke the trivial function.
BM_StatusOrFactoryFailLongMsg(::testing::benchmark::State & state)663 void BM_StatusOrFactoryFailLongMsg(::testing::benchmark::State& state) {
664 BenchmarkFactory<BenchmarkType> factory;
665 for (auto s : state) {
666 StatusOr<BenchmarkType*> result = factory.StatusOrFactoryFailLongMsg();
667 if (result.ok()) {
668 result.ValueOrDie()->DoWork();
669 }
670 }
671 }
672 BENCHMARK(BM_StatusOrFactoryFailLongMsg);
673
674 } // namespace
675 } // namespace tensorflow
676