Skip to content

Commit d5c1ef0

Browse files
committed
Add observer to cookbook
1 parent 5e490fe commit d5c1ef0

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

docs/cookbook/Chapter6.dox

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,71 @@ As we increase the number of taskflow objects,
236236
the implementation without sharing the executor encounters more context switches among threads.
237237
This overhead reflected on the slower runtime (15482 vs 14341 on 128 taskflow objects).
238238

239+
@section C6MonitorThreadActivities Monitor Thread Activities
240+
241+
Knowing the thread activities is very important for performance analysis.
242+
Cpp-Taskflow provides a tf::ExecutorObserver to let users create an observer to record an executor's task execution. The following example shows creating an observer through the executor's tf::Executor::make_observer method.
243+
244+
@code{.cpp}
245+
tf::Taskflow taskflow;
246+
auto observer = taskflow.share_executor()->make_observer<tf::ExecutorObserver>();
247+
@endcode
248+
249+
Note that each executor can only have an observer at a time and creating observer during task execution
250+
will result in undefined behavior. An observer will automatically record the start and end timestamps
251+
of each executed task. Users can query, dump or remove the timestamps through the tf::ExecutorObserver::num_tasks,
252+
tf::ExecutorObserver::dump and tf::ExecutorObserver::clear methods.
253+
254+
@code{.cpp}
255+
1. tf::Taskflow taskflow;
256+
2. auto observer = taskflow.share_executor()->make_observer<tf::ExecutorObserver>();
257+
3. taskflow.emplace([](){}, [](){}, [](){}, [](){});
258+
4. taskflow.wait_for_all();
259+
5.
260+
6. // Query the total number of tasks (number of timestamp pairs)
261+
7. auto num_tasks = observer->num_tasks();
262+
8.
263+
9. // Dump the timestamps in JSON format
264+
10. std::string timestamps = observer->dump();
265+
11.
266+
12. // Remove all timestamps
267+
13. observer->clear();
268+
@endcode
269+
270+
Debrief:
271+
272+
@li Line 2-4 creates an observer and a task dependency graph with four tasks and dispatch the tasks to execution.
273+
@li Line 7 query the total number of tasks (number of timestamp pair) through observer
274+
@li Line 10 dump the timestamps to a std::string in JSON format
275+
@li Line 13 remove all timestamps in the observer
276+
277+
Cpp-Taskflow also supports visualization of thread activities. Users can use Chrome (or Chromium on Linux)
278+
browser following below steps to plot the executed tasks as temporal sequences:
279+
280+
@li Step 1: dump the timestamps in observer to a JSON file
281+
@li Step 2: launch the Chrome browser and open a tab with the url: chrome://tracing
282+
@li Step 3: load the JSON file
283+
284+
The resuling plot is like this:
285+
286+
@image html images/timeline.png width=80%
287+
288+
Tasks will be categorized by the executing thread and each task is named with @em i_j where @em i is the thread id and
289+
@em j is the task number. Users can select individual task to know its duration and pan or zoom the timeline to go into
290+
a detailed view.
291+
292+
Users can also customize methods of observer to monitor the behavior of an executor through
293+
inheriting the tf::ExecutorObserverInterface class.
294+
There are three methods users can customize: tf::ExecutorObserverInterface::set_up,
295+
tf::ExecutorObserverInterface::on_entry and tf::ExecutorObserverInterface::on_exit.
296+
The tf::ExecutorObserverInterface::set_up takes the number of threads in an executor as the input argument and
297+
an executor calls this method once to prepare the observer after the observer is constructed.
298+
A thread will call the tf::ExecutorObserverInterface::on_entry and tf::ExecutorObserverInterface::on_exit methods respectively
299+
before and after executing a task, and both methods take the thread id as input argument. Notice that the
300+
tf::ExecutorObserverInterface::on_entry and tf::ExecutorObserverInterface::on_exit can be invoked by multiple
301+
threads concurrently and therefore they must be thread-safe.
302+
303+
239304
*/
240305

241306
}

0 commit comments

Comments
 (0)