From: Andrii Grynenko Date: Wed, 14 Dec 2016 01:50:27 +0000 (-0800) Subject: Update fibers GDB docs X-Git-Tag: v2016.12.19.00~22 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f2203c94f2545d2597a64a1e9d0d173874a40415;p=folly.git Update fibers GDB docs Reviewed By: yfeldblum Differential Revision: D4323918 fbshipit-source-id: 8dcd4ef3629fff061a9f149093ef1fe087f1c7e2 --- diff --git a/folly/fibers/README.md b/folly/fibers/README.md index 3dfdef4a..c9947d3d 100644 --- a/folly/fibers/README.md +++ b/folly/fibers/README.md @@ -15,13 +15,13 @@ fiberManager.addTask([&]() { std::cout << "Task 1: start" << std::endl; baton.wait(); - std::cout << "Task 1: after baton.wait()" << std::endl; + std::cout << "Task 1: after baton.wait()" << std::endl; }); fiberManager.addTask([&]() { std::cout << "Task 2: start" << std::endl; baton.post(); - std::cout << "Task 2: after baton.post()" << std::endl; + std::cout << "Task 2: after baton.post()" << std::endl; }); evb.loop(); @@ -76,7 +76,7 @@ fiberManager.addTask([&]() { std::cout << "Task: start" << std::endl; baton.wait(); - std::cout << "Task: after baton.wait()" << std::endl; + std::cout << "Task: after baton.wait()" << std::endl; }); evb.loop(); @@ -116,7 +116,7 @@ ... Response response; fibers::Baton baton; - + asyncCall(request, [&](Response r) mutable { response = std::move(r); baton.post(); @@ -190,7 +190,7 @@
fiberManager.addTask([]() {
   ...
   auto response = asyncCallFuture(request).get();
-
+  
   // Now response holds response returned by the async call
   ...
 }
@@ -229,7 +229,7 @@
...
 Context context;
-
+ 
 asyncCall(request, [request, context](Response response) mutable {
   doSomething(request, response, context);
 });
@@ -242,7 +242,7 @@
   Context context;
 
   auto response = fiberCall(request);
-
+ 
   doSomething(request, response, context);
   ...
 });
@@ -308,7 +308,7 @@

First fiber-task will grab a lock and then suspend waiting on a fibers::Baton. Then second fiber-task will be run and it will try to grab a lock. Unlike system threads, fiber-task can be only suspended explicitly, so the whole system thread will be blocked waiting on the lock, and we end up with a dead-lock.

-

There're generally two ways we can solve this problem. Ideally we would re-design the program to never not hold any locks when fiber-task is suspended. However if we are absolutely sure we need that lock - folly::fibers library provides some fiber-task-aware lock implementations (e.g. +

There're generally two ways we can solve this problem. Ideally we would re-design the program to never not hold any locks when fiber-task is suspended. However if we are absolutely sure we need that lock - folly::fibers library provides some fiber-task-aware lock implementations (e.g. TimedMutex).

APIs

fibers::Baton #

All of the features of folly::fibers library are actually built on top a single synchronization primitive called Baton. fibers::Baton is a fiber-specific version of folly::Baton. It only supports two basic operations: wait() and post(). Whenever wait() is called on the Baton, the current thread or fiber-task is suspended, until post() is called on the same Baton. wait() does not suspend the thread or fiber-task if post() was already called on the Baton. Please refer to Baton for more detailed documentation.

@@ -410,7 +410,7 @@ }); auto future2 = fiberManager.addTaskRemoteFuture([]() { ... - }); + }); auto result1 = future1.get(); auto result2 = future2.get(); @@ -427,9 +427,9 @@

collectN

-

collectAny

+

collectAll

-

collectN

+

collectAny

forEach

@@ -468,85 +468,78 @@

Such fibers::FiberManager will be automatically destroyed, when folly::EventBase is destroyed.

-
NOTE: folly::fibers doesn't support killing fiber-tasks in-flight (for similar reasons you can't kill a thread). If fibers::FiberManager has any outstanding fiber-tasks, when folly::EventBase is being destroyed, it will keep running the event loop until all those tasks are finished.

GDB integration

folly::fibers provide some GDB extensions which can be very useful for debugging. To load them simply the following in dbg console:

+
NOTE: folly::fibers doesn't support killing fiber-tasks in-flight (for similar reasons you can't kill a thread). If fibers::FiberManager has any outstanding fiber-tasks, when folly::EventBase is being destroyed, it will keep running the event loop until all those tasks are finished.

GDB integration

folly::fibers provides some GDB extensions which can be very useful for debugging. To load them simply run the following in GDB console:

-
source 'folly/fibers/scripts/utils.gdb'
+
fbload folly_fibers
-

Show all FiberManagers #

+

Find all FiberManagers #

-

You can use print_folly_fiber_manager_map to list all fibers::FiberManagers and folly::EventBases they are attached to.

+

You can use $get_fiber_manager_map_evb() and $get_fiber_manager_map_vevb() to get folly::EventBase => fibers::FiberManager and folly::VirtualEventBase => fibers::FiberManager mappings respectively:

-
(gdb) print_folly_fiber_manager_map
-  Global FiberManager map has 2 entries.
-    (folly::EventBase*)0x7fffffffdb60 -> (folly::fibers::FiberManager*)0x7ffff5b58480
-    (folly::EventBase*)0x7fffffffd930 -> (folly::fibers::FiberManager*)0x7ffff5b58300
+
(gdb) fbload stl
+(gdb) p $get_fiber_manager_map_evb()
+$2 = std::unordered_map with 2 elements = {
+  [0x7fffffffda80] = std::unique_ptr<folly::fibers::FiberManager> containing 0x7ffff5c22a00,
+  [0x7fffffffd850] = std::unique_ptr<folly::fibers::FiberManager> containing 0x7ffff5c22800
+}

This will only list fibers::FiberManagers created using fibers::getFiberManager() function.

- - -

You can use print_folly_fiber_manager (and passing a pointer to valid fibers::FiberManager object) to print the state of given fibers::FiberManager.

- -
(gdb) print_folly_fiber_manager &manager
-  (folly::fibers::FiberManager*)0x7fffffffdbe0
-
-  Fibers active: 3
-  Fibers allocated: 3
-  Fibers pool size: 0
-  Active fiber: (folly::fibers::Fiber*)(nil)
-  Current fiber: (folly::fibers::Fiber*)(nil)
-
-  Active fibers:
-    (folly::fibers::Fiber*)0x7ffff5b5b000   State: Awaiting
-    (folly::fibers::Fiber*)0x7ffff5b5b300   State: Awaiting
-    (folly::fibers::Fiber*)0x7ffff5b5b600   State: Awaiting
- -

It will list all active fibers::Fiber objects, which are running fiber-tasks and their states.

- - - -

If you have a fibers::Fiber, which is running some fiber-task, you can print its state using print_folly_fiber command.

- -
(gdb) print_folly_fiber 0x7ffff5b5b600
-  (folly::fibers::Fiber*)0x7ffff5b5b600
-
-  State: Awaiting
-  Backtrace:
-    #0 at 0x5a22a8 in folly::fibers::FiberManager::deactivateFiber(folly::fibers::Fiber*) + 194 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out
-/gen/folly/experimental/fibers/fibers-test
-    #1 at 0x5a1606 in folly::fibers::Fiber::preempt(folly::fibers::Fiber::State)::{lambda()#1}::operator()() + 598 in section .text of /mnt/fio0/andrii/fbsou
-rce/fbcode/buck-out/gen/folly/experimental/fibers/fibers-test
-    #2 at 0x5a17f8 in folly::fibers::Fiber::preempt(folly::fibers::Fiber::State) + 176 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen/foll
-y/experimental/fibers/fibers-test
-    #3 at 0x43a76e in void folly::fibers::Baton::waitFiber<folly::fibers::FirstArgOf<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() con
-st::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}, void>::type::value_type folly::fibers::await
-<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(foll
-y::fibers::Promise<int>)#1}>(folly::fibers::Promise<int>&&)::{lambda()#1}>(folly::fibers::FiberManager&, folly::fibers::FirstArgOf<FiberManager_collectAll_Te
-st::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}
-, void>::type::value_type folly::fibers::await<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::
-{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}>(folly::fibers::Promise<int>&&)::{lambda()#1}) + 110 in section .text of /mnt/fio0/
-andrii/fbsource/fbcode/buck-out/gen/folly/experimental/fibers/fibers-test
-    #4 at 0x42fa89 in void folly::fibers::Baton::wait<folly::fibers::FirstArgOf<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{
-lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}, void>::type::value_type folly::fibers::await<Fibe
-rManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fi
-bers::Promise<int>)#1}>(folly::fibers::Promise<int>&&)::{lambda()#1}>(folly::fibers::FirstArgOf<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::opera
-tor()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}, void>::type::value_type folly::fi
-bers::await<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{
-lambda(folly::fibers::Promise<int>)#1}>(folly::fibers::Promise<int>&&)::{lambda()#1}) + 105 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen
-/folly/experimental/fibers/fibers-test
-    #5 at 0x425921 in folly::fibers::FirstArgOf<FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const:
-:{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}, void>::type::value_type folly::fibers::await<FiberManager_collectAll_Test::TestBo
-dy()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda(folly::fibers::Promise<int>)#1}>(folly::f
-ibers::Promise<int>&&) + 80 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen/folly/experimental/fibers/fibers-test
-    #6 at 0x415e9a in FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const::{lambda()#1}::operator()(
-) const + 36 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen/folly/experimental/fibers/fibers-test
-    #7 at 0x42faf9 in std::_Function_handler<int (), FiberManager_collectAll_Test::TestBody()::{lambda()#1}::operator()() const::{lambda()#1}::operator()() c
-onst::{lambda()#1}>::_M_invoke(std::_Any_data const&) + 32 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen/folly/fibers/fibers
--test
-    #8 at 0x479d5c in std::function<int ()>::operator()() const + 50 in section .text of /mnt/fio0/andrii/fbsource/fbcode/buck-out/gen/folly/experimental/fib
-ers/fibers-test
-    ...
- -

It will print the state of the fiber-task and if fiber-task is currently awaiting - also prints its stack-trace.

+

Printing a FiberManager #

+ +

Given a pointer to a fibers::FiberManager you can get a list of all its active fibers:

+ +
(gdb) p *((folly::fibers::FiberManager*)0x7ffff5c22800)
+$4 = folly::fibers::FiberManager = {
+  0x7ffff5d23380 = folly::fibers::Fiber = {
+    state = Awaiting immediate,
+    backtrace available = true
+  }
+}
+ +

Printing a fiber-task #

+ +

Given a pointer to a fibers::Fiber, which is running some fiber-task, you can get its current state:

+ +
(gdb) p *((folly::fibers::Fiber*)0x7ffff5d23380)
+$5 = folly::fibers::Fiber = {
+  state = Awaiting immediate,
+  backtrace available = true
+}
+ +

Activating a fiber-task #

+ +

Every fibers::Fiber, which is suspended (and so has its backtrace available), can be activated. To activate a fiber-task you can either use fiber GDB command, passing a fibers::Fiber pointer to it:

+ +
(gdb) fiber 0x7ffff5d23380
+Fiber 140737317581696 activated. You can call 'bt' now.
+ +

or simply call activate() on a fibers::Fiber object:

+ +
(gdb) p ((folly::fibers::Fiber*)0x7ffff5d23380)->activate()
+$6 = "Fiber 0x7ffff5d23380 activated. You can call 'bt' now."
+ +

Once fiber-task is activated you can explore its stack using bt and frame commands, just like a regular thread.

+ +
(gdb) bt
+#1  0x00000000005497e9 in folly::fibers::FiberImpl::deactivate() (this=0x7ffff5d233a0)
+    at buck-out/dbg/gen/folly/fibers/fibers_core#default,headers/folly/fibers/BoostContextCompatibility.h:105
+#2  0x000000000054996d in folly::fibers::FiberManager::deactivateFiber(folly::fibers::Fiber*) (this=0x7ffff5c22800, fiber=0x7ffff5d23380)
+    at buck-out/dbg/gen/folly/fibers/fibers_core#default,headers/folly/fibers/FiberManagerInternal-inl.h:103
+#3  0x0000000000548b91 in folly::fibers::Fiber::<lambda()>::operator()(void) (__closure=0x7ffff59ffb20) at folly/fibers/Fiber.cpp:175
+#4  0x0000000000548d78 in folly::fibers::Fiber::preempt(folly::fibers::Fiber::State) (this=0x7ffff5d23380, state=folly::fibers::Fiber::AWAITING_IMMEDIATE)
+    at folly/fibers/Fiber.cpp:185
+#5  0x000000000043bcc6 in folly::fibers::FiberManager::runInMainContext<FiberManager_nestedFiberManagers_Test::TestBody()::<lambda()>::<lambda()> >(<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0x111bdb>) (this=0x7ffff5c22800, func=<unknown type in   /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0x111bdb>)
+    at buck-out/dbg/gen/folly/fibers/fibers_core#default,headers/folly/fibers/FiberManagerInternal-inl.h:459
+#6  0x00000000004300f3 in folly::fibers::runInMainContext<FiberManager_nestedFiberManagers_Test::TestBody()::<lambda()>::<lambda()> >(<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0xf7caa>) (func=<unknown type in   /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0xf7caa>)
+    at buck-out/dbg/gen/folly/fibers/fibers_core#default,headers/folly/fibers/FiberManagerInternal.h:551
+#7  0x0000000000422101 in FiberManager_nestedFiberManagers_Test::<lambda()>::operator()(void) const (__closure=0x7ffff5d23450)
+    at folly/fibers/test/FibersTest.cpp:1537
+...
+ +

To deactivate previously activated fiber-task and switch back to the stack of current thread simply use fiber-deactivate GDB command:

+ +
(gdb) fiber-deactivate
+Fiber de-activated.
NOTE: For running (i.e. not suspended) fiber-task, you can simply switch to the system thread which owns it and use regular GDB commands for debugging.
\ No newline at end of file