641c8db8111842d235b28eb74fe2c68173563c3d
[folly.git] / folly / experimental / fibers / test / FibersTest.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <atomic>
17 #include <thread>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <folly/Benchmark.h>
23 #include <folly/Memory.h>
24
25 #include <folly/experimental/fibers/AddTasks.h>
26 #include <folly/experimental/fibers/EventBaseLoopController.h>
27 #include <folly/experimental/fibers/FiberManager.h>
28 #include <folly/experimental/fibers/GenericBaton.h>
29 #include <folly/experimental/fibers/SimpleLoopController.h>
30 #include <folly/experimental/fibers/WhenN.h>
31
32 using namespace folly::fibers;
33
34 using folly::Try;
35
36 TEST(FiberManager, batonTimedWaitTimeout) {
37   bool taskAdded = false;
38   size_t iterations = 0;
39
40   FiberManager manager(folly::make_unique<SimpleLoopController>());
41   auto& loopController =
42     dynamic_cast<SimpleLoopController&>(manager.loopController());
43
44   auto loopFunc = [&]() {
45   if (!taskAdded) {
46       manager.addTask(
47         [&]() {
48           Baton baton;
49
50           auto res = baton.timed_wait(std::chrono::milliseconds(230));
51
52           EXPECT_FALSE(res);
53           EXPECT_EQ(5, iterations);
54
55           loopController.stop();
56         }
57       );
58       manager.addTask(
59         [&]() {
60           Baton baton;
61
62           auto res = baton.timed_wait(std::chrono::milliseconds(130));
63
64           EXPECT_FALSE(res);
65           EXPECT_EQ(3, iterations);
66
67           loopController.stop();
68         }
69       );
70       taskAdded = true;
71     } else {
72       std::this_thread::sleep_for(std::chrono::milliseconds(50));
73       iterations ++;
74     }
75   };
76
77   loopController.loop(std::move(loopFunc));
78 }
79
80 TEST(FiberManager, batonTimedWaitPost) {
81   bool taskAdded = false;
82   size_t iterations = 0;
83   Baton* baton_ptr;
84
85   FiberManager manager(folly::make_unique<SimpleLoopController>());
86   auto& loopController =
87     dynamic_cast<SimpleLoopController&>(manager.loopController());
88
89   auto loopFunc = [&]() {
90     if (!taskAdded) {
91       manager.addTask(
92         [&]() {
93           Baton baton;
94           baton_ptr = &baton;
95
96           auto res = baton.timed_wait(std::chrono::milliseconds(130));
97
98           EXPECT_TRUE(res);
99           EXPECT_EQ(2, iterations);
100
101           loopController.stop();
102         }
103       );
104       taskAdded = true;
105     } else {
106       std::this_thread::sleep_for(std::chrono::milliseconds(50));
107       iterations ++;
108       if (iterations == 2) {
109         baton_ptr->post();
110       }
111     }
112   };
113
114   loopController.loop(std::move(loopFunc));
115 }
116
117 TEST(FiberManager, batonTimedWaitTimeoutEvb) {
118   size_t tasksComplete = 0;
119
120   folly::EventBase evb;
121
122   FiberManager manager(folly::make_unique<EventBaseLoopController>());
123   dynamic_cast<EventBaseLoopController&>(
124     manager.loopController()).attachEventBase(evb);
125
126   auto task = [&](size_t timeout_ms) {
127     Baton baton;
128
129     auto start = EventBaseLoopController::Clock::now();
130     auto res = baton.timed_wait(std::chrono::milliseconds(timeout_ms));
131     auto finish = EventBaseLoopController::Clock::now();
132
133     EXPECT_FALSE(res);
134
135     auto duration_ms =
136       std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
137
138     EXPECT_GT(duration_ms.count(), timeout_ms - 50);
139     EXPECT_LT(duration_ms.count(), timeout_ms + 50);
140
141     if (++tasksComplete == 2) {
142       evb.terminateLoopSoon();
143     }
144   };
145
146   evb.runInEventBaseThread([&]() {
147     manager.addTask(
148       [&]() {
149         task(500);
150       }
151     );
152     manager.addTask(
153       [&]() {
154         task(250);
155       }
156     );
157   });
158
159   evb.loopForever();
160
161   EXPECT_EQ(2, tasksComplete);
162 }
163
164 TEST(FiberManager, batonTimedWaitPostEvb) {
165   size_t tasksComplete = 0;
166
167   folly::EventBase evb;
168
169   FiberManager manager(folly::make_unique<EventBaseLoopController>());
170   dynamic_cast<EventBaseLoopController&>(
171     manager.loopController()).attachEventBase(evb);
172
173   evb.runInEventBaseThread([&]() {
174       manager.addTask([&]() {
175           Baton baton;
176
177           evb.tryRunAfterDelay([&]() {
178               baton.post();
179             },
180             100);
181
182           auto start = EventBaseLoopController::Clock::now();
183           auto res = baton.timed_wait(std::chrono::milliseconds(130));
184           auto finish = EventBaseLoopController::Clock::now();
185
186           EXPECT_TRUE(res);
187
188           auto duration_ms = std::chrono::duration_cast<
189             std::chrono::milliseconds>(finish - start);
190
191           EXPECT_TRUE(duration_ms.count() > 95 &&
192                       duration_ms.count() < 110);
193
194           if (++tasksComplete == 1) {
195             evb.terminateLoopSoon();
196           }
197         });
198     });
199
200   evb.loopForever();
201
202   EXPECT_EQ(1, tasksComplete);
203 }
204
205 TEST(FiberManager, batonTryWait) {
206
207   FiberManager manager(folly::make_unique<SimpleLoopController>());
208
209   // Check if try_wait and post work as expected
210   Baton b;
211
212   manager.addTask([&](){
213     while (!b.try_wait()) {
214     }
215   });
216   auto thr = std::thread([&](){
217     std::this_thread::sleep_for(std::chrono::milliseconds(300));
218     b.post();
219   });
220
221   manager.loopUntilNoReady();
222   thr.join();
223
224   Baton c;
225
226   // Check try_wait without post
227   manager.addTask([&](){
228     int cnt = 100;
229     while (cnt && !c.try_wait()) {
230       cnt--;
231     }
232     EXPECT_TRUE(!c.try_wait()); // must still hold
233     EXPECT_EQ(cnt, 0);
234   });
235
236   manager.loopUntilNoReady();
237 }
238
239 TEST(FiberManager, genericBatonFiberWait) {
240   FiberManager manager(folly::make_unique<SimpleLoopController>());
241
242   GenericBaton b;
243   bool fiberRunning = false;
244
245   manager.addTask([&](){
246     EXPECT_EQ(manager.hasActiveFiber(), true);
247     fiberRunning = true;
248     b.wait();
249     fiberRunning = false;
250   });
251
252   EXPECT_FALSE(fiberRunning);
253   manager.loopUntilNoReady();
254   EXPECT_TRUE(fiberRunning); // ensure fiber still active
255
256   auto thr = std::thread([&](){
257     std::this_thread::sleep_for(std::chrono::milliseconds(300));
258     b.post();
259   });
260
261   while (fiberRunning) {
262     manager.loopUntilNoReady();
263   }
264
265   thr.join();
266 }
267
268 TEST(FiberManager, genericBatonThreadWait) {
269   FiberManager manager(folly::make_unique<SimpleLoopController>());
270   GenericBaton b;
271   std::atomic<bool> threadWaiting(false);
272
273   auto thr = std::thread([&](){
274     threadWaiting = true;
275     b.wait();
276     threadWaiting = false;
277   });
278
279   while (!threadWaiting) {}
280   std::this_thread::sleep_for(std::chrono::milliseconds(300));
281
282   manager.addTask([&](){
283     EXPECT_EQ(manager.hasActiveFiber(), true);
284     EXPECT_TRUE(threadWaiting);
285     b.post();
286     while(threadWaiting) {}
287   });
288
289   manager.loopUntilNoReady();
290   thr.join();
291 }
292
293 TEST(FiberManager, addTasksNoncopyable) {
294   std::vector<Promise<int>> pendingFibers;
295   bool taskAdded = false;
296
297   FiberManager manager(folly::make_unique<SimpleLoopController>());
298   auto& loopController =
299     dynamic_cast<SimpleLoopController&>(manager.loopController());
300
301   auto loopFunc = [&]() {
302     if (!taskAdded) {
303       manager.addTask(
304         [&]() {
305           std::vector<std::function<std::unique_ptr<int>()>> funcs;
306           for (size_t i = 0; i < 3; ++i) {
307             funcs.push_back(
308               [i, &pendingFibers]() {
309                 await([&pendingFibers](Promise<int> promise) {
310                     pendingFibers.push_back(std::move(promise));
311                   });
312                 return folly::make_unique<int>(i*2 + 1);
313               }
314             );
315           }
316
317           auto iter = addTasks(funcs.begin(), funcs.end());
318
319           size_t n = 0;
320           while (iter.hasNext()) {
321             auto result = iter.awaitNext();
322             EXPECT_EQ(2 * iter.getTaskID() + 1, *result);
323             EXPECT_GE(2 - n, pendingFibers.size());
324             ++n;
325           }
326           EXPECT_EQ(3, n);
327         }
328       );
329       taskAdded = true;
330     } else if (pendingFibers.size()) {
331       pendingFibers.back().setValue(0);
332       pendingFibers.pop_back();
333     } else {
334       loopController.stop();
335     }
336   };
337
338   loopController.loop(std::move(loopFunc));
339 }
340
341 TEST(FiberManager, addTasksThrow) {
342   std::vector<Promise<int>> pendingFibers;
343   bool taskAdded = false;
344
345   FiberManager manager(folly::make_unique<SimpleLoopController>());
346   auto& loopController =
347     dynamic_cast<SimpleLoopController&>(manager.loopController());
348
349   auto loopFunc = [&]() {
350     if (!taskAdded) {
351       manager.addTask(
352         [&]() {
353           std::vector<std::function<int()>> funcs;
354           for (size_t i = 0; i < 3; ++i) {
355             funcs.push_back(
356               [i, &pendingFibers]() {
357                 await([&pendingFibers](Promise<int> promise) {
358                     pendingFibers.push_back(std::move(promise));
359                   });
360                 if (i % 2 == 0) {
361                   throw std::runtime_error("Runtime");
362                 }
363                 return i*2 + 1;
364               }
365             );
366           }
367
368           auto iter = addTasks(funcs.begin(), funcs.end());
369
370           size_t n = 0;
371           while (iter.hasNext()) {
372             try {
373               int result = iter.awaitNext();
374               EXPECT_EQ(1, iter.getTaskID() % 2);
375               EXPECT_EQ(2 * iter.getTaskID() + 1, result);
376             } catch (...) {
377               EXPECT_EQ(0, iter.getTaskID() % 2);
378             }
379             EXPECT_GE(2 - n, pendingFibers.size());
380             ++n;
381           }
382           EXPECT_EQ(3, n);
383         }
384       );
385       taskAdded = true;
386     } else if (pendingFibers.size()) {
387       pendingFibers.back().setValue(0);
388       pendingFibers.pop_back();
389     } else {
390       loopController.stop();
391     }
392   };
393
394   loopController.loop(std::move(loopFunc));
395 }
396
397 TEST(FiberManager, addTasksVoid) {
398   std::vector<Promise<int>> pendingFibers;
399   bool taskAdded = false;
400
401   FiberManager manager(folly::make_unique<SimpleLoopController>());
402   auto& loopController =
403     dynamic_cast<SimpleLoopController&>(manager.loopController());
404
405   auto loopFunc = [&]() {
406     if (!taskAdded) {
407       manager.addTask(
408         [&]() {
409           std::vector<std::function<void()>> funcs;
410           for (size_t i = 0; i < 3; ++i) {
411             funcs.push_back(
412               [i, &pendingFibers]() {
413                 await([&pendingFibers](Promise<int> promise) {
414                     pendingFibers.push_back(std::move(promise));
415                   });
416               }
417             );
418           }
419
420           auto iter = addTasks(funcs.begin(), funcs.end());
421
422           size_t n = 0;
423           while (iter.hasNext()) {
424             iter.awaitNext();
425             EXPECT_GE(2 - n, pendingFibers.size());
426             ++n;
427           }
428           EXPECT_EQ(3, n);
429         }
430       );
431       taskAdded = true;
432     } else if (pendingFibers.size()) {
433       pendingFibers.back().setValue(0);
434       pendingFibers.pop_back();
435     } else {
436       loopController.stop();
437     }
438   };
439
440   loopController.loop(std::move(loopFunc));
441 }
442
443 TEST(FiberManager, addTasksVoidThrow) {
444   std::vector<Promise<int>> pendingFibers;
445   bool taskAdded = false;
446
447   FiberManager manager(folly::make_unique<SimpleLoopController>());
448   auto& loopController =
449     dynamic_cast<SimpleLoopController&>(manager.loopController());
450
451   auto loopFunc = [&]() {
452     if (!taskAdded) {
453       manager.addTask(
454         [&]() {
455           std::vector<std::function<void()>> funcs;
456           for (size_t i = 0; i < 3; ++i) {
457             funcs.push_back(
458               [i, &pendingFibers]() {
459                 await([&pendingFibers](Promise<int> promise) {
460                     pendingFibers.push_back(std::move(promise));
461                   });
462                 if (i % 2 == 0) {
463                   throw std::runtime_error("");
464                 }
465               }
466             );
467           }
468
469           auto iter = addTasks(funcs.begin(), funcs.end());
470
471           size_t n = 0;
472           while (iter.hasNext()) {
473             try {
474               iter.awaitNext();
475               EXPECT_EQ(1, iter.getTaskID() % 2);
476             } catch (...) {
477               EXPECT_EQ(0, iter.getTaskID() % 2);
478             }
479             EXPECT_GE(2 - n, pendingFibers.size());
480             ++n;
481           }
482           EXPECT_EQ(3, n);
483         }
484       );
485       taskAdded = true;
486     } else if (pendingFibers.size()) {
487       pendingFibers.back().setValue(0);
488       pendingFibers.pop_back();
489     } else {
490       loopController.stop();
491     }
492   };
493
494   loopController.loop(std::move(loopFunc));
495 }
496
497 TEST(FiberManager, reserve) {
498   std::vector<Promise<int>> pendingFibers;
499   bool taskAdded = false;
500
501   FiberManager manager(folly::make_unique<SimpleLoopController>());
502   auto& loopController =
503     dynamic_cast<SimpleLoopController&>(manager.loopController());
504
505   auto loopFunc = [&]() {
506     if (!taskAdded) {
507       manager.addTask(
508         [&]() {
509           std::vector<std::function<void()>> funcs;
510           for (size_t i = 0; i < 3; ++i) {
511             funcs.push_back(
512               [&pendingFibers]() {
513                 await([&pendingFibers](Promise<int> promise) {
514                     pendingFibers.push_back(std::move(promise));
515                   });
516               }
517             );
518           }
519
520           auto iter = addTasks(funcs.begin(), funcs.end());
521
522           iter.reserve(2);
523           EXPECT_TRUE(iter.hasCompleted());
524           EXPECT_TRUE(iter.hasPending());
525           EXPECT_TRUE(iter.hasNext());
526
527           iter.awaitNext();
528           EXPECT_TRUE(iter.hasCompleted());
529           EXPECT_TRUE(iter.hasPending());
530           EXPECT_TRUE(iter.hasNext());
531
532           iter.awaitNext();
533           EXPECT_FALSE(iter.hasCompleted());
534           EXPECT_TRUE(iter.hasPending());
535           EXPECT_TRUE(iter.hasNext());
536
537           iter.awaitNext();
538           EXPECT_FALSE(iter.hasCompleted());
539           EXPECT_FALSE(iter.hasPending());
540           EXPECT_FALSE(iter.hasNext());
541         }
542       );
543       taskAdded = true;
544     } else if (pendingFibers.size()) {
545       pendingFibers.back().setValue(0);
546       pendingFibers.pop_back();
547     } else {
548       loopController.stop();
549     }
550   };
551
552   loopController.loop(std::move(loopFunc));
553 }
554
555 TEST(FiberManager, forEach) {
556   std::vector<Promise<int>> pendingFibers;
557   bool taskAdded = false;
558
559   FiberManager manager(folly::make_unique<SimpleLoopController>());
560   auto& loopController =
561     dynamic_cast<SimpleLoopController&>(manager.loopController());
562
563   auto loopFunc = [&]() {
564     if (!taskAdded) {
565       manager.addTask(
566         [&]() {
567           std::vector<std::function<int()>> funcs;
568           for (size_t i = 0; i < 3; ++i) {
569             funcs.push_back(
570               [i, &pendingFibers]() {
571                 await([&pendingFibers](Promise<int> promise) {
572                     pendingFibers.push_back(std::move(promise));
573                   });
574                 return i * 2 + 1;
575               }
576             );
577           }
578
579           std::vector<std::pair<size_t, int>> results;
580           forEach(funcs.begin(), funcs.end(),
581             [&results](size_t id, int result) {
582               results.emplace_back(id, result);
583             });
584           EXPECT_EQ(3, results.size());
585           EXPECT_TRUE(pendingFibers.empty());
586           for (size_t i = 0; i < 3; ++i) {
587             EXPECT_EQ(results[i].first * 2 + 1, results[i].second);
588           }
589         }
590       );
591       taskAdded = true;
592     } else if (pendingFibers.size()) {
593       pendingFibers.back().setValue(0);
594       pendingFibers.pop_back();
595     } else {
596       loopController.stop();
597     }
598   };
599
600   loopController.loop(std::move(loopFunc));
601 }
602
603 TEST(FiberManager, collectN) {
604   std::vector<Promise<int>> pendingFibers;
605   bool taskAdded = false;
606
607   FiberManager manager(folly::make_unique<SimpleLoopController>());
608   auto& loopController =
609     dynamic_cast<SimpleLoopController&>(manager.loopController());
610
611   auto loopFunc = [&]() {
612     if (!taskAdded) {
613       manager.addTask(
614         [&]() {
615           std::vector<std::function<int()>> funcs;
616           for (size_t i = 0; i < 3; ++i) {
617             funcs.push_back(
618               [i, &pendingFibers]() {
619                 await([&pendingFibers](Promise<int> promise) {
620                     pendingFibers.push_back(std::move(promise));
621                   });
622                 return i*2 + 1;
623               }
624             );
625           }
626
627           auto results = collectN(funcs.begin(), funcs.end(), 2);
628           EXPECT_EQ(2, results.size());
629           EXPECT_EQ(1, pendingFibers.size());
630           for (size_t i = 0; i < 2; ++i) {
631             EXPECT_EQ(results[i].first*2 + 1, results[i].second);
632           }
633         }
634       );
635       taskAdded = true;
636     } else if (pendingFibers.size()) {
637       pendingFibers.back().setValue(0);
638       pendingFibers.pop_back();
639     } else {
640       loopController.stop();
641     }
642   };
643
644   loopController.loop(std::move(loopFunc));
645 }
646
647 TEST(FiberManager, collectNThrow) {
648   std::vector<Promise<int>> pendingFibers;
649   bool taskAdded = false;
650
651   FiberManager manager(folly::make_unique<SimpleLoopController>());
652   auto& loopController =
653     dynamic_cast<SimpleLoopController&>(manager.loopController());
654
655   auto loopFunc = [&]() {
656     if (!taskAdded) {
657       manager.addTask(
658         [&]() {
659           std::vector<std::function<int()>> funcs;
660           for (size_t i = 0; i < 3; ++i) {
661             funcs.push_back(
662               [i, &pendingFibers]() {
663                 await([&pendingFibers](Promise<int> promise) {
664                     pendingFibers.push_back(std::move(promise));
665                   });
666                 throw std::runtime_error("Runtime");
667                 return i*2+1;
668               }
669             );
670           }
671
672           try {
673             collectN(funcs.begin(), funcs.end(), 2);
674           } catch (...) {
675             EXPECT_EQ(1, pendingFibers.size());
676           }
677         }
678       );
679       taskAdded = true;
680     } else if (pendingFibers.size()) {
681       pendingFibers.back().setValue(0);
682       pendingFibers.pop_back();
683     } else {
684       loopController.stop();
685     }
686   };
687
688   loopController.loop(std::move(loopFunc));
689 }
690
691 TEST(FiberManager, collectNVoid) {
692   std::vector<Promise<int>> pendingFibers;
693   bool taskAdded = false;
694
695   FiberManager manager(folly::make_unique<SimpleLoopController>());
696   auto& loopController =
697     dynamic_cast<SimpleLoopController&>(manager.loopController());
698
699   auto loopFunc = [&]() {
700     if (!taskAdded) {
701       manager.addTask(
702         [&]() {
703           std::vector<std::function<void()>> funcs;
704           for (size_t i = 0; i < 3; ++i) {
705             funcs.push_back(
706               [i, &pendingFibers]() {
707                 await([&pendingFibers](Promise<int> promise) {
708                     pendingFibers.push_back(std::move(promise));
709                   });
710               }
711             );
712           }
713
714           auto results = collectN(funcs.begin(), funcs.end(), 2);
715           EXPECT_EQ(2, results.size());
716           EXPECT_EQ(1, pendingFibers.size());
717         }
718       );
719       taskAdded = true;
720     } else if (pendingFibers.size()) {
721       pendingFibers.back().setValue(0);
722       pendingFibers.pop_back();
723     } else {
724       loopController.stop();
725     }
726   };
727
728   loopController.loop(std::move(loopFunc));
729 }
730
731 TEST(FiberManager, collectNVoidThrow) {
732   std::vector<Promise<int>> pendingFibers;
733   bool taskAdded = false;
734
735   FiberManager manager(folly::make_unique<SimpleLoopController>());
736   auto& loopController =
737     dynamic_cast<SimpleLoopController&>(manager.loopController());
738
739   auto loopFunc = [&]() {
740     if (!taskAdded) {
741       manager.addTask(
742         [&]() {
743           std::vector<std::function<void()>> funcs;
744           for (size_t i = 0; i < 3; ++i) {
745             funcs.push_back(
746               [i, &pendingFibers]() {
747                 await([&pendingFibers](Promise<int> promise) {
748                     pendingFibers.push_back(std::move(promise));
749                   });
750                 throw std::runtime_error("Runtime");
751               }
752             );
753           }
754
755           try {
756             collectN(funcs.begin(), funcs.end(), 2);
757           } catch (...) {
758             EXPECT_EQ(1, pendingFibers.size());
759           }
760         }
761       );
762       taskAdded = true;
763     } else if (pendingFibers.size()) {
764       pendingFibers.back().setValue(0);
765       pendingFibers.pop_back();
766     } else {
767       loopController.stop();
768     }
769   };
770
771   loopController.loop(std::move(loopFunc));
772 }
773
774 TEST(FiberManager, collectAll) {
775   std::vector<Promise<int>> pendingFibers;
776   bool taskAdded = false;
777
778   FiberManager manager(folly::make_unique<SimpleLoopController>());
779   auto& loopController =
780     dynamic_cast<SimpleLoopController&>(manager.loopController());
781
782   auto loopFunc = [&]() {
783     if (!taskAdded) {
784       manager.addTask(
785         [&]() {
786           std::vector<std::function<int()>> funcs;
787           for (size_t i = 0; i < 3; ++i) {
788             funcs.push_back(
789               [i, &pendingFibers]() {
790                 await([&pendingFibers](Promise<int> promise) {
791                     pendingFibers.push_back(std::move(promise));
792                   });
793                 return i*2+1;
794               }
795             );
796           }
797
798           auto results = collectAll(funcs.begin(), funcs.end());
799           EXPECT_TRUE(pendingFibers.empty());
800           for (size_t i = 0; i < 3; ++i) {
801             EXPECT_EQ(i*2+1, results[i]);
802           }
803         }
804       );
805       taskAdded = true;
806     } else if (pendingFibers.size()) {
807       pendingFibers.back().setValue(0);
808       pendingFibers.pop_back();
809     } else {
810       loopController.stop();
811     }
812   };
813
814   loopController.loop(std::move(loopFunc));
815 }
816
817 TEST(FiberManager, collectAllVoid) {
818   std::vector<Promise<int>> pendingFibers;
819   bool taskAdded = false;
820
821   FiberManager manager(folly::make_unique<SimpleLoopController>());
822   auto& loopController =
823     dynamic_cast<SimpleLoopController&>(manager.loopController());
824
825   auto loopFunc = [&]() {
826     if (!taskAdded) {
827       manager.addTask(
828         [&]() {
829           std::vector<std::function<void()>> funcs;
830           for (size_t i = 0; i < 3; ++ i) {
831             funcs.push_back(
832               [i, &pendingFibers]() {
833                 await([&pendingFibers](Promise<int> promise) {
834                     pendingFibers.push_back(std::move(promise));
835                   });
836               }
837             );
838           }
839
840           collectAll(funcs.begin(), funcs.end());
841           EXPECT_TRUE(pendingFibers.empty());
842         }
843       );
844       taskAdded = true;
845     } else if (pendingFibers.size()) {
846       pendingFibers.back().setValue(0);
847       pendingFibers.pop_back();
848     } else {
849       loopController.stop();
850     }
851   };
852
853   loopController.loop(std::move(loopFunc));
854 }
855
856 TEST(FiberManager, collectAny) {
857   std::vector<Promise<int>> pendingFibers;
858   bool taskAdded = false;
859
860   FiberManager manager(folly::make_unique<SimpleLoopController>());
861   auto& loopController =
862     dynamic_cast<SimpleLoopController&>(manager.loopController());
863
864   auto loopFunc = [&]() {
865     if (!taskAdded) {
866       manager.addTask(
867         [&]() {
868           std::vector<std::function<int()> > funcs;
869           for (size_t i = 0; i < 3; ++ i) {
870             funcs.push_back(
871               [i, &pendingFibers]() {
872                 await([&pendingFibers](Promise<int> promise) {
873                     pendingFibers.push_back(std::move(promise));
874                   });
875                 if (i == 1) {
876                   throw std::runtime_error("This exception will be ignored");
877                 }
878                 return i*2+1;
879               }
880             );
881           }
882
883           auto result = collectAny(funcs.begin(), funcs.end());
884           EXPECT_EQ(2, pendingFibers.size());
885           EXPECT_EQ(2, result.first);
886           EXPECT_EQ(2*2+1, result.second);
887         }
888       );
889       taskAdded = true;
890     } else if (pendingFibers.size()) {
891       pendingFibers.back().setValue(0);
892       pendingFibers.pop_back();
893     } else {
894       loopController.stop();
895     }
896   };
897
898   loopController.loop(std::move(loopFunc));
899 }
900
901 namespace {
902 /* Checks that this function was run from a main context,
903    by comparing an address on a stack to a known main stack address
904    and a known related fiber stack address.  The assumption
905    is that fiber stack and main stack will be far enough apart,
906    while any two values on the same stack will be close. */
907 void expectMainContext(bool& ran, int* mainLocation, int* fiberLocation) {
908   int here;
909   /* 2 pages is a good guess */
910   constexpr ssize_t DISTANCE = 0x2000 / sizeof(int);
911   if (fiberLocation) {
912     EXPECT_TRUE(std::abs(&here - fiberLocation) > DISTANCE);
913   }
914   if (mainLocation) {
915     EXPECT_TRUE(std::abs(&here - mainLocation) < DISTANCE);
916   }
917
918   EXPECT_FALSE(ran);
919   ran = true;
920 }
921 }
922
923 TEST(FiberManager, runInMainContext) {
924   FiberManager manager(folly::make_unique<SimpleLoopController>());
925   auto& loopController =
926     dynamic_cast<SimpleLoopController&>(manager.loopController());
927
928   bool checkRan = false;
929
930   int mainLocation;
931   manager.runInMainContext(
932     [&]() {
933       expectMainContext(checkRan, &mainLocation, nullptr);
934     });
935   EXPECT_TRUE(checkRan);
936
937   checkRan = false;
938
939   manager.addTask(
940     [&]() {
941       int stackLocation;
942       runInMainContext(
943         [&]() {
944           expectMainContext(checkRan, &mainLocation, &stackLocation);
945         });
946       EXPECT_TRUE(checkRan);
947     }
948   );
949
950   loopController.loop(
951     [&]() {
952       loopController.stop();
953     }
954   );
955
956   EXPECT_TRUE(checkRan);
957 }
958
959 TEST(FiberManager, addTaskFinally) {
960   FiberManager manager(folly::make_unique<SimpleLoopController>());
961   auto& loopController =
962     dynamic_cast<SimpleLoopController&>(manager.loopController());
963
964   bool checkRan = false;
965
966   int mainLocation;
967
968   manager.addTaskFinally(
969     [&]() {
970       return 1234;
971     },
972     [&](Try<int>&& result) {
973       EXPECT_EQ(result.value(), 1234);
974
975       expectMainContext(checkRan, &mainLocation, nullptr);
976     }
977   );
978
979   EXPECT_FALSE(checkRan);
980
981   loopController.loop(
982     [&]() {
983       loopController.stop();
984     }
985   );
986
987   EXPECT_TRUE(checkRan);
988 }
989
990 TEST(FiberManager, fibersPoolWithinLimit) {
991   FiberManager::Options opts;
992   opts.maxFibersPoolSize = 5;
993
994   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
995   auto& loopController =
996     dynamic_cast<SimpleLoopController&>(manager.loopController());
997
998   size_t fibersRun = 0;
999
1000   for (size_t i = 0; i < 5; ++i) {
1001     manager.addTask(
1002       [&]() {
1003         ++fibersRun;
1004       }
1005     );
1006   }
1007   loopController.loop(
1008     [&]() {
1009       loopController.stop();
1010     }
1011   );
1012
1013   EXPECT_EQ(5, fibersRun);
1014   EXPECT_EQ(5, manager.fibersAllocated());
1015   EXPECT_EQ(5, manager.fibersPoolSize());
1016
1017   for (size_t i = 0; i < 5; ++i) {
1018     manager.addTask(
1019       [&]() {
1020         ++fibersRun;
1021       }
1022     );
1023   }
1024   loopController.loop(
1025     [&]() {
1026       loopController.stop();
1027     }
1028   );
1029
1030   EXPECT_EQ(10, fibersRun);
1031   EXPECT_EQ(5, manager.fibersAllocated());
1032   EXPECT_EQ(5, manager.fibersPoolSize());
1033 }
1034
1035 TEST(FiberManager, fibersPoolOverLimit) {
1036   FiberManager::Options opts;
1037   opts.maxFibersPoolSize = 5;
1038
1039   FiberManager manager(folly::make_unique<SimpleLoopController>(), opts);
1040   auto& loopController =
1041     dynamic_cast<SimpleLoopController&>(manager.loopController());
1042
1043   size_t fibersRun = 0;
1044
1045   for (size_t i = 0; i < 10; ++i) {
1046     manager.addTask(
1047       [&]() {
1048         ++fibersRun;
1049       }
1050     );
1051   }
1052
1053   EXPECT_EQ(0, fibersRun);
1054   EXPECT_EQ(10, manager.fibersAllocated());
1055   EXPECT_EQ(0, manager.fibersPoolSize());
1056
1057   loopController.loop(
1058     [&]() {
1059       loopController.stop();
1060     }
1061   );
1062
1063   EXPECT_EQ(10, fibersRun);
1064   EXPECT_EQ(5, manager.fibersAllocated());
1065   EXPECT_EQ(5, manager.fibersPoolSize());
1066 }
1067
1068 TEST(FiberManager, remoteFiberBasic) {
1069   FiberManager manager(folly::make_unique<SimpleLoopController>());
1070   auto& loopController =
1071     dynamic_cast<SimpleLoopController&>(manager.loopController());
1072
1073   int result[2];
1074   result[0] = result[1] = 0;
1075   folly::Optional<Promise<int>> savedPromise[2];
1076   manager.addTask(
1077     [&] () {
1078       result[0] = await([&] (Promise<int> promise) {
1079           savedPromise[0] = std::move(promise);
1080         });
1081     });
1082   manager.addTask(
1083     [&] () {
1084       result[1] = await([&] (Promise<int> promise) {
1085           savedPromise[1] = std::move(promise);
1086         });
1087     });
1088
1089   manager.loopUntilNoReady();
1090
1091   EXPECT_TRUE(savedPromise[0].hasValue());
1092   EXPECT_TRUE(savedPromise[1].hasValue());
1093   EXPECT_EQ(0, result[0]);
1094   EXPECT_EQ(0, result[1]);
1095
1096   std::thread remoteThread0{
1097     [&] () {
1098       savedPromise[0]->setValue(42);
1099     }
1100   };
1101   std::thread remoteThread1{
1102     [&] () {
1103       savedPromise[1]->setValue(43);
1104     }
1105   };
1106   remoteThread0.join();
1107   remoteThread1.join();
1108   EXPECT_EQ(0, result[0]);
1109   EXPECT_EQ(0, result[1]);
1110   /* Should only have scheduled once */
1111   EXPECT_EQ(1, loopController.remoteScheduleCalled());
1112
1113   manager.loopUntilNoReady();
1114   EXPECT_EQ(42, result[0]);
1115   EXPECT_EQ(43, result[1]);
1116 }
1117
1118 TEST(FiberManager, addTaskRemoteBasic) {
1119   FiberManager manager(folly::make_unique<SimpleLoopController>());
1120
1121   int result[2];
1122   result[0] = result[1] = 0;
1123   folly::Optional<Promise<int>> savedPromise[2];
1124
1125   std::thread remoteThread0{
1126     [&] () {
1127       manager.addTaskRemote(
1128         [&] () {
1129           result[0] = await([&] (Promise<int> promise) {
1130               savedPromise[0] = std::move(promise);
1131             });
1132         });
1133     }
1134   };
1135   std::thread remoteThread1{
1136     [&] () {
1137       manager.addTaskRemote(
1138         [&] () {
1139           result[1] = await([&] (Promise<int> promise) {
1140               savedPromise[1] = std::move(promise);
1141             });
1142         });
1143     }
1144   };
1145   remoteThread0.join();
1146   remoteThread1.join();
1147
1148   manager.loopUntilNoReady();
1149
1150   EXPECT_TRUE(savedPromise[0].hasValue());
1151   EXPECT_TRUE(savedPromise[1].hasValue());
1152   EXPECT_EQ(0, result[0]);
1153   EXPECT_EQ(0, result[1]);
1154
1155   savedPromise[0]->setValue(42);
1156   savedPromise[1]->setValue(43);
1157
1158   EXPECT_EQ(0, result[0]);
1159   EXPECT_EQ(0, result[1]);
1160
1161   manager.loopUntilNoReady();
1162   EXPECT_EQ(42, result[0]);
1163   EXPECT_EQ(43, result[1]);
1164 }
1165
1166 TEST(FiberManager, remoteHasTasks) {
1167   size_t counter = 0;
1168   FiberManager fm(folly::make_unique<SimpleLoopController>());
1169   std::thread remote([&]() {
1170     fm.addTaskRemote([&]() {
1171       ++counter;
1172     });
1173   });
1174
1175   remote.join();
1176
1177   while (fm.hasTasks()) {
1178     fm.loopUntilNoReady();
1179   }
1180
1181   EXPECT_FALSE(fm.hasTasks());
1182   EXPECT_EQ(counter, 1);
1183 }
1184
1185 TEST(FiberManager, remoteHasReadyTasks) {
1186   int result = 0;
1187   folly::Optional<Promise<int>> savedPromise;
1188   FiberManager fm(folly::make_unique<SimpleLoopController>());
1189   std::thread remote([&]() {
1190     fm.addTaskRemote([&]() {
1191       result = await([&](Promise<int> promise) {
1192         savedPromise = std::move(promise);
1193       });
1194       EXPECT_TRUE(fm.hasTasks());
1195     });
1196   });
1197
1198   remote.join();
1199   EXPECT_TRUE(fm.hasTasks());
1200
1201   fm.loopUntilNoReady();
1202   EXPECT_TRUE(fm.hasTasks());
1203
1204   std::thread remote2([&](){
1205     savedPromise->setValue(47);
1206   });
1207   remote2.join();
1208   EXPECT_TRUE(fm.hasTasks());
1209
1210   fm.loopUntilNoReady();
1211   EXPECT_FALSE(fm.hasTasks());
1212
1213   EXPECT_EQ(result, 47);
1214 }
1215
1216 template <typename Data>
1217 void testFiberLocal() {
1218   FiberManager fm(LocalType<Data>(),
1219                   folly::make_unique<SimpleLoopController>());
1220
1221   fm.addTask([]() {
1222       EXPECT_EQ(42, local<Data>().value);
1223
1224       local<Data>().value = 43;
1225
1226       addTask([]() {
1227           EXPECT_EQ(43, local<Data>().value);
1228
1229           local<Data>().value = 44;
1230
1231           addTask([]() {
1232               EXPECT_EQ(44, local<Data>().value);
1233             });
1234         });
1235    });
1236
1237   fm.addTask([&]() {
1238       EXPECT_EQ(42, local<Data>().value);
1239
1240       local<Data>().value = 43;
1241
1242       fm.addTaskRemote([]() {
1243           EXPECT_EQ(43, local<Data>().value);
1244         });
1245     });
1246
1247   fm.addTask([]() {
1248       EXPECT_EQ(42, local<Data>().value);
1249       local<Data>().value = 43;
1250
1251       auto task = []() {
1252         EXPECT_EQ(43, local<Data>().value);
1253         local<Data>().value = 44;
1254       };
1255       std::vector<std::function<void()>> tasks{task};
1256       collectAny(tasks.begin(), tasks.end());
1257
1258       EXPECT_EQ(43, local<Data>().value);
1259     });
1260
1261   fm.loopUntilNoReady();
1262   EXPECT_FALSE(fm.hasTasks());
1263 }
1264
1265 TEST(FiberManager, fiberLocal) {
1266   struct SimpleData {
1267     int value{42};
1268   };
1269
1270   testFiberLocal<SimpleData>();
1271 }
1272
1273 TEST(FiberManager, fiberLocalHeap) {
1274   struct LargeData {
1275     char _[1024*1024];
1276     int value{42};
1277   };
1278
1279   testFiberLocal<LargeData>();
1280 }
1281
1282 TEST(FiberManager, fiberLocalDestructor) {
1283   struct CrazyData {
1284     size_t data{42};
1285
1286     ~CrazyData() {
1287       if (data == 41) {
1288         addTask([]() {
1289             EXPECT_EQ(42, local<CrazyData>().data);
1290             // Make sure we don't have infinite loop
1291             local<CrazyData>().data = 0;
1292           });
1293       }
1294     }
1295   };
1296
1297   FiberManager fm(LocalType<CrazyData>(),
1298                   folly::make_unique<SimpleLoopController>());
1299
1300   fm.addTask([]() {
1301       local<CrazyData>().data = 41;
1302     });
1303
1304   fm.loopUntilNoReady();
1305   EXPECT_FALSE(fm.hasTasks());
1306 }
1307
1308 TEST(FiberManager, yieldTest) {
1309   FiberManager manager(folly::make_unique<SimpleLoopController>());
1310   auto& loopController =
1311     dynamic_cast<SimpleLoopController&>(manager.loopController());
1312
1313   bool checkRan = false;
1314
1315   manager.addTask(
1316     [&]() {
1317       manager.yield();
1318       checkRan = true;
1319     }
1320   );
1321
1322   loopController.loop(
1323     [&]() {
1324       if (checkRan) {
1325         loopController.stop();
1326       }
1327     }
1328   );
1329
1330   EXPECT_TRUE(checkRan);
1331 }
1332
1333 TEST(FiberManager, RequestContext) {
1334   FiberManager fm(folly::make_unique<SimpleLoopController>());
1335
1336   bool checkRun1 = false;
1337   bool checkRun2 = false;
1338   bool checkRun3 = false;
1339
1340   folly::fibers::Baton baton1;
1341   folly::fibers::Baton baton2;
1342   folly::fibers::Baton baton3;
1343
1344   folly::RequestContext::create();
1345   auto rcontext1 = folly::RequestContext::get();
1346   fm.addTask([&]() {
1347       EXPECT_EQ(rcontext1, folly::RequestContext::get());
1348       baton1.wait([&]() {
1349           EXPECT_EQ(rcontext1, folly::RequestContext::get());
1350         });
1351       EXPECT_EQ(rcontext1, folly::RequestContext::get());
1352       runInMainContext([&]() {
1353           EXPECT_EQ(rcontext1, folly::RequestContext::get());
1354         });
1355       checkRun1 = true;
1356     });
1357
1358   folly::RequestContext::create();
1359   auto rcontext2 = folly::RequestContext::get();
1360   fm.addTaskRemote([&]() {
1361       EXPECT_EQ(rcontext2, folly::RequestContext::get());
1362       baton2.wait();
1363       EXPECT_EQ(rcontext2, folly::RequestContext::get());
1364       checkRun2 = true;
1365     });
1366
1367   folly::RequestContext::create();
1368   auto rcontext3 = folly::RequestContext::get();
1369   fm.addTaskFinally([&]() {
1370       EXPECT_EQ(rcontext3, folly::RequestContext::get());
1371       baton3.wait();
1372       EXPECT_EQ(rcontext3, folly::RequestContext::get());
1373
1374       return folly::Unit();
1375     },
1376     [&](Try<folly::Unit>&& t) {
1377       EXPECT_EQ(rcontext3, folly::RequestContext::get());
1378       checkRun3 = true;
1379     });
1380
1381   folly::RequestContext::create();
1382   auto rcontext = folly::RequestContext::get();
1383
1384   fm.loopUntilNoReady();
1385   EXPECT_EQ(rcontext, folly::RequestContext::get());
1386
1387   baton1.post();
1388   EXPECT_EQ(rcontext, folly::RequestContext::get());
1389   fm.loopUntilNoReady();
1390   EXPECT_TRUE(checkRun1);
1391   EXPECT_EQ(rcontext, folly::RequestContext::get());
1392
1393   baton2.post();
1394   EXPECT_EQ(rcontext, folly::RequestContext::get());
1395   fm.loopUntilNoReady();
1396   EXPECT_TRUE(checkRun2);
1397   EXPECT_EQ(rcontext, folly::RequestContext::get());
1398
1399   baton3.post();
1400   EXPECT_EQ(rcontext, folly::RequestContext::get());
1401   fm.loopUntilNoReady();
1402   EXPECT_TRUE(checkRun3);
1403   EXPECT_EQ(rcontext, folly::RequestContext::get());
1404 }
1405
1406 TEST(FiberManager, resizePeriodically) {
1407   FiberManager::Options opts;
1408   opts.fibersPoolResizePeriodMs = 300;
1409   opts.maxFibersPoolSize = 5;
1410
1411   FiberManager manager(folly::make_unique<EventBaseLoopController>(), opts);
1412
1413   folly::EventBase evb;
1414   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1415     .attachEventBase(evb);
1416
1417   std::vector<Baton> batons(10);
1418
1419   size_t tasksRun = 0;
1420   for (size_t i = 0; i < 30; ++i) {
1421     manager.addTask([i, &batons, &tasksRun]() {
1422       ++tasksRun;
1423       // Keep some fibers active indefinitely
1424       if (i < batons.size()) {
1425         batons[i].wait();
1426       }
1427     });
1428   }
1429
1430   EXPECT_EQ(0, tasksRun);
1431   EXPECT_EQ(30, manager.fibersAllocated());
1432   EXPECT_EQ(0, manager.fibersPoolSize());
1433
1434   evb.loopOnce();
1435   EXPECT_EQ(30, tasksRun);
1436   EXPECT_EQ(30, manager.fibersAllocated());
1437   // Can go over maxFibersPoolSize, 10 of 30 fibers still active
1438   EXPECT_EQ(20, manager.fibersPoolSize());
1439
1440   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1441   evb.loopOnce(); // no fibers active in this period
1442   EXPECT_EQ(30, manager.fibersAllocated());
1443   EXPECT_EQ(20, manager.fibersPoolSize());
1444
1445   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1446   evb.loopOnce(); // should shrink fibers pool to maxFibersPoolSize
1447   EXPECT_EQ(15, manager.fibersAllocated());
1448   EXPECT_EQ(5, manager.fibersPoolSize());
1449
1450   for (size_t i = 0; i < batons.size(); ++i) {
1451     batons[i].post();
1452   }
1453   evb.loopOnce();
1454   EXPECT_EQ(15, manager.fibersAllocated());
1455   EXPECT_EQ(15, manager.fibersPoolSize());
1456
1457   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1458   evb.loopOnce(); // 10 fibers active in last period
1459   EXPECT_EQ(10, manager.fibersAllocated());
1460   EXPECT_EQ(10, manager.fibersPoolSize());
1461
1462   std::this_thread::sleep_for(std::chrono::milliseconds(400));
1463   evb.loopOnce();
1464   EXPECT_EQ(5, manager.fibersAllocated());
1465   EXPECT_EQ(5, manager.fibersPoolSize());
1466 }
1467
1468 TEST(FiberManager, batonWaitTimeoutHandler) {
1469   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1470
1471   folly::EventBase evb;
1472   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1473     .attachEventBase(evb);
1474
1475   size_t fibersRun = 0;
1476   Baton baton;
1477   Baton::TimeoutHandler timeoutHandler;
1478
1479   manager.addTask([&]() {
1480     baton.wait(timeoutHandler);
1481     ++fibersRun;
1482   });
1483   manager.loopUntilNoReady();
1484
1485   EXPECT_FALSE(baton.try_wait());
1486   EXPECT_EQ(0, fibersRun);
1487
1488   timeoutHandler.scheduleTimeout(std::chrono::milliseconds(250));
1489   std::this_thread::sleep_for(std::chrono::milliseconds(500));
1490
1491   EXPECT_FALSE(baton.try_wait());
1492   EXPECT_EQ(0, fibersRun);
1493
1494   evb.loopOnce();
1495   manager.loopUntilNoReady();
1496
1497   EXPECT_EQ(1, fibersRun);
1498 }
1499
1500 TEST(FiberManager, batonWaitTimeoutMany) {
1501   FiberManager manager(folly::make_unique<EventBaseLoopController>());
1502
1503   folly::EventBase evb;
1504   dynamic_cast<EventBaseLoopController&>(manager.loopController())
1505     .attachEventBase(evb);
1506
1507   constexpr size_t kNumTimeoutTasks = 10000;
1508   size_t tasksCount = kNumTimeoutTasks;
1509
1510   // We add many tasks to hit timeout queue deallocation logic.
1511   for (size_t i = 0; i < kNumTimeoutTasks; ++i) {
1512     manager.addTask([&]() {
1513       Baton baton;
1514       Baton::TimeoutHandler timeoutHandler;
1515
1516       folly::fibers::addTask([&] {
1517         timeoutHandler.scheduleTimeout(std::chrono::milliseconds(1000));
1518       });
1519
1520       baton.wait(timeoutHandler);
1521       if (--tasksCount == 0) {
1522         evb.terminateLoopSoon();
1523       }
1524     });
1525   }
1526
1527   evb.loopForever();
1528 }
1529
1530 static size_t sNumAwaits;
1531
1532 void runBenchmark(size_t numAwaits, size_t toSend) {
1533   sNumAwaits = numAwaits;
1534
1535   FiberManager fiberManager(folly::make_unique<SimpleLoopController>());
1536   auto& loopController =
1537     dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
1538
1539   std::queue<Promise<int>> pendingRequests;
1540   static const size_t maxOutstanding = 5;
1541
1542   auto loop = [&fiberManager, &loopController, &pendingRequests, &toSend]() {
1543     if (pendingRequests.size() == maxOutstanding || toSend == 0) {
1544       if (pendingRequests.empty()) {
1545         return;
1546       }
1547       pendingRequests.front().setValue(0);
1548       pendingRequests.pop();
1549     } else {
1550       fiberManager.addTask([&pendingRequests]() {
1551           for (size_t i = 0; i < sNumAwaits; ++i) {
1552             auto result = await(
1553               [&pendingRequests](Promise<int> promise) {
1554                 pendingRequests.push(std::move(promise));
1555               });
1556             DCHECK_EQ(result, 0);
1557           }
1558         });
1559
1560       if (--toSend == 0) {
1561         loopController.stop();
1562       }
1563     }
1564   };
1565
1566   loopController.loop(std::move(loop));
1567 }
1568
1569 BENCHMARK(FiberManagerBasicOneAwait, iters) {
1570   runBenchmark(1, iters);
1571 }
1572
1573 BENCHMARK(FiberManagerBasicFiveAwaits, iters) {
1574   runBenchmark(5, iters);
1575 }
1576
1577 BENCHMARK(FiberManagerAllocateDeallocatePattern, iters) {
1578   static const size_t kNumAllocations = 10000;
1579
1580   FiberManager::Options opts;
1581   opts.maxFibersPoolSize = 0;
1582
1583   FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1584
1585   for (size_t iter = 0; iter < iters; ++iter) {
1586     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1587
1588     size_t fibersRun = 0;
1589
1590     for (size_t i = 0; i < kNumAllocations; ++i) {
1591       fiberManager.addTask(
1592         [&fibersRun] {
1593           ++fibersRun;
1594         }
1595       );
1596       fiberManager.loopUntilNoReady();
1597     }
1598
1599     EXPECT_EQ(10000, fibersRun);
1600     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1601   }
1602 }
1603
1604 BENCHMARK(FiberManagerAllocateLargeChunk, iters) {
1605   static const size_t kNumAllocations = 10000;
1606
1607   FiberManager::Options opts;
1608   opts.maxFibersPoolSize = 0;
1609
1610   FiberManager fiberManager(folly::make_unique<SimpleLoopController>(), opts);
1611
1612   for (size_t iter = 0; iter < iters; ++iter) {
1613     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1614
1615     size_t fibersRun = 0;
1616
1617     for (size_t i = 0; i < kNumAllocations; ++i) {
1618       fiberManager.addTask(
1619         [&fibersRun] {
1620           ++fibersRun;
1621         }
1622       );
1623     }
1624
1625     fiberManager.loopUntilNoReady();
1626
1627     EXPECT_EQ(10000, fibersRun);
1628     EXPECT_EQ(0, fiberManager.fibersPoolSize());
1629   }
1630 }