TaskTracer: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Update usage)
(/* Labels)
 
(13 intermediate revisions by 4 users not shown)
Line 1: Line 1:
== Introduction ==
== Introduction ==
TaskTracer aims at the '''correlation''' between Tasks and Runnables, across threads and processes.
TaskTracer remembers the '''correlation''' between Tasks and Runnables, across threads and processes.


By looking at a task, TaskTracer tells you:
By looking at a task, TaskTracer tells you:
* The “source events” of this task.
* The “source events” of this task.
** IO events: touch events, key events, wifi daemon signal
** IO events: touch events, key events, wifi daemon signal
* Where it is dispatched from.
* Who, the other task, does create a task.
* The timing a task was dispatched, run, and stopped.
== Get log files ==


== How to use TaskTracer ==
Compile Gecko or Firefox with following line in mozconfig.
=== mozilla-central ===
'''1. Build and flash (built-in)'''


cd B2G
  ac_add_options --enable-tasktracer
export MOZ_TASK_TRACER=1; ./build.sh gecko
./flash.sh gecko


'''2. Get TaskTracer Converter'''
Start logging with Gecko Profiler Addon. There is an option in the
control panel of the addon to enable TaskTracer.


https://bugzilla.mozilla.org/show_bug.cgi?id=1098217
Attach gdb to Firefox process, the chrome process, and run following
command in gdb.


Since Converter hasn't been landed yet, please manually download the patch and apply to your B2G repo.
  (gdb) call profiler_save_profile_to_file_async(0.0, "/abs/to/logfile")
  (gdb) continue


'''3. Start profiling'''
Waiting for a couple seconds, the file would be created.


./profile.sh start -f tasktracer
== Dump log ==
Get [https://bitbucket.org/thinker/tttools tttools]
  python dumplog.py /path/to/logfile


You can still combine the "tasktracer" feature with other supported flags of "start" command. For example, <code> ./profile.sh start -f tasktracer,js,leaf -i 50</code> will start profiling on all processes with tasktracer and default features, and longer the sampling interval to 50 milliseconds.
== Task ==


Please note that because TaskTracer is design to record the correlation of tasks between threads and processes, enabling this feature will start profiling on all processes, which says, later commands such as <code>./profile.sh start -p aProcessName</code> will be invalid.
A task is dispatched to a task queue at the time (in ms) given by
|dispatchTime| attribute of the |Task| object. It is an array because
of a runnable can be dispatched and ran for several times.


'''4. Capture profiling results'''
|begin| is the time that the runnable/task was started to run.  |end|
is the time where the task finish it's work.


./profile.sh capture
  {'begin': [u'1472463888021'],
  'dispatchTime': [u'1472463888021'],
  'end': [u'1472463888021'],
  'label': [],
  'parent': u'0',
  'process': 22525,
  'sourceEventId': u'0',
  'sourceEventType': u'0',
  'taskId': u'96744138362318',
  'thread': 22525,
  'timeDuration': 0,
  'vptr': '??'},


In additional to the original results of GeckoProfiler, turning on <code>-f tasktracer</code> should find a section of TaskTracer data inserted into each output files. The first recording period is from the time of <code>./profile.sh start</code> till the time of first <code>./profile.sh capture</code>, the next recording period is then from the time of this <code>capture</code> till the next <code>capture</code>...and so on.


<code>./profile.sh stop</code> kills all processes and reboots b2g.
== Load log in python ==
  import tttools
  profileobject = tttools.loadRawProfile('/abs/to/logfile')


=== v1.3T ===
== Parent tasks ==
1. Get the source code of TaskTracer.


  git clone https://github.com/shellylin/gecko-dev/tree/tt-1.3t
Parent task of a task is the one create and dispatch the task. You
can find the parent task, parent's parent, ... and all ancestors with
the following Python instructions.


2. Build and flash to a real device.
  taskIdsOfAncestors = profileobject.findAncestors(GivenTaskId)
  import pprint
  pprint.pprint(profileobject.findTasks(taskIdsOfAncestors))


cd B2G
== Followers ==
export MOZ_TASK_TRACER=1; ./build.sh gecko
./flash.sh gecko


3. Get the source code of data retriever and data converter.
Followers of a task are tasks that is created by the given task or
it's followers.


git clone https://github.com/ginayeh/task-tracer-converter
  taskIdsOfFollowers = profileobject.findFollowers(GivenTaskId)
  import pprint
  pprint.pprint(profileobject.findTasks(taskIdsOfFollowers))


4. Start profiling.
== Blocker tasks ==


cd task-tracer-converter
You can find what tasks are blocked by the different in time of
./tasktracer.sh start
|dispatchTime| and |begin|.


5. Stop profiling.
  tasks = profileobject.findTasks(profileobject.findAncestors(GivenTaskId))
  for task in tasks:
    queuingTIme = long(task.begin[0]) - long(task.dispatchTime[0])
    print 'task: %s, thread: %d, queuingTime: %d' % (task.taskId,
                                                    task.thread,
    queuingTime)


  ./tasktracer.sh stop
The more time a task staying in the queue, the more time the task is
blocked by other tasks. You can find what other tasks blocked a task
with following instructions.


The raw log is written into ''task_tracer_data.logcat''.
  task = profileobject.findTask(BlockedTaskId)
  blockerIds =
    profileobject.findTasksStartInTimeThread(int(task.dispatchTime[0]),
                                            int(task.begin[0]),
    task.thread)
  blockers = profileobject.findTasks(blockerIds)
  pprint.pprint(blockers)


6. Get memory maps from the real device.
== Labels ==


  mkdir mmaps
You may need to attach some information or strings on tasks and to see
./tasktracer.sh get_mmaps
strings in the log to help you to identify specific tasks. Following
C++ code in Gecko would add a label, i.e. a string, on the current
running task of this thread.


The memory maps pulled out from the real device are put under mmaps directory automatically.
  #ifdef MOZ_TASK_TRACER
  #include "GeckoTaskTracer.h"
  #endif
  ...
  #ifdef MOZ_TASK_TRACER
  mozilla::tasktracer::AddLabel("Event [%s] ...", str...);
  #endif


7. Prepare data for extracting class/task name.
Javascript adds labels with a special prefix.


./prepare-data.sh mmaps ''$objdir''
  console.log("#tt# Log message"); // #tt# is the prefix.


Two intermediate files are generated for later use: ''mem_offset'', ''symbol''.
For the case of labeling at begin and end of a scope, |AutoScopedLabel| is a helper class to do that.


8. Convert raw log to JSON format.
  {
  #ifdef MOZ_TASK_TRACER
    AutoScopedLabel label("Event [%s] ...", str...);  // label "Begin Event [...]..."
  #endif
    // do something ....
  } // label "End Event [...]..."


  python task_tracer_converter.py -i task_tracer_data.logcat [-o task_tracer_data.json] [-w]
The "Begin ..." label would be added when the instance of |AutoScopedLabel| was created. And, "End ..." label would be added when the instance was destroyed.


Default output filename: ''task_tracer_data.json''.
== DESIGN ==


== How to read the profile using Nephthys ==
TaskTracer has 5 types of logs in its log files,
DISPATCH, BEGIN, END, VTABLE, and LABEL.
They are used to remember


Import the json file to Nephthys, http://alivedise.github.io/nephthys/
- what the task created and dispatched a new task to
  a target thread,
- the time a task was started to run at the target thread,
- the time a task had done its works,
- the type (vtalbe of the class) of the runnable of a given task, and
- labels that denote what was happened in a task.


== Reference links ==
=== TASK ID ===
* {{bug|995058}} - [Meta] TaskTracer and Nephthys
* {{bug|908995}} - [B2G] Task tracer
* {{bug|916409}} - Data retriever for task tracer
* {{bug|916410}} - Show data generated by Task Tracer in Cleopatra
* {{bug|956620}} - [B2G] Task tracer converter
** https://github.com/ginayeh/task-tracer-converter
* {{bug|992454}} - [B2G] Integrate Task tracer&Nephthys with GeckoProfiler&Cleopatra
* Nephthys
** http://alivedise.github.io/nephthys/
** https://github.com/alivedise/nephthys/tree/gh-pages
* FoxGuide
** https://addons.mozilla.org/en-US/firefox/addon/foxguide/


== TODO ==
Each type of logs has a time stamp to denote when it was happened, and
* Thread pool
a task ID to uniquely identify a tasks.  To make the running code
* CpuTime
knowning which task is running at a thread, the ID of the running task
* Integrate with Cleopatra
is stored in the TLS, e.q. thread local storage, when the event loop
* Nested loop
of the thread starts to run it.  That means when a new task was
* Ruler
created and dispatched, TaskTracer got the task ID of the running task
of current thread from TLS, and denote it as the creator/parent of the
new one.
 
The IDs of a task and its parent task (from TLS) were recorded in a
DISPATCH log when it was dispatched to correlates a task and its
parent task.
 
When an IPC message was sent, a new task was created and dispatched at
receiving side to handle the message.  TaskTracer stores the task ID
of the sender of a message in its header, and uses that ID as the
parent task ID of the task handling the message at receiving site.
With this, TaskTracer correlates tasks over processes.
 
=== SOURCE EVENT ID AND TYPE ===
 
Not all tasks are always created by another task.  For example, a
mouse event would create and dispatch a task to handle it, but the
mouse event itself is no task.  TaskTracer calls mouse events or other
events from the kernel as source events.  Every source event has an
unique ID to identify it, and assign a type to identify whether it is
a mouse event, keyboard event, ..., or network event.  They are source
event IDs and source event types.
 
The tasks created by source events have no parent task ID, the value of
its parent task ID is identical to its task ID.  With this rule, users
know a task was created for handling a source event if its task ID is
identical to its parent task ID.
 
Source event ID and type would be stored in TLS of threads.  They are
also retrieved from TLS and stored in the new runnable of a new task
when the new task is created/dispatched.  When a new task was started
to run, the source event ID and type stored on it will be retrieved
and stored to TLS too.  That means source event ID and type would
passing along all tasks created for the source event directly or
indirectly.  That means they are also dispatched along IPC messages.
 
=== VTABLE ===
 
For C++, every virtual class, that means a class having at least one
virtual method, has a vtab to store entry points of its virtual
methods.  A VTABLE log contains the address of vtab of the concrete
class of an instance of Runnable (a task).  With the address of the
vtab of a task, TaskTracer can get the concrete class name of the task
by symbolicating.  People can understand the purpose of a task by its
name.

Latest revision as of 08:30, 13 March 2017

Introduction

TaskTracer remembers the correlation between Tasks and Runnables, across threads and processes.

By looking at a task, TaskTracer tells you:

  • The “source events” of this task.
    • IO events: touch events, key events, wifi daemon signal
  • Who, the other task, does create a task.
  • The timing a task was dispatched, run, and stopped.

Get log files

Compile Gecko or Firefox with following line in mozconfig.

 ac_add_options --enable-tasktracer

Start logging with Gecko Profiler Addon. There is an option in the control panel of the addon to enable TaskTracer.

Attach gdb to Firefox process, the chrome process, and run following command in gdb.

 (gdb) call profiler_save_profile_to_file_async(0.0, "/abs/to/logfile")
 (gdb) continue

Waiting for a couple seconds, the file would be created.

Dump log

Get tttools

 python dumplog.py /path/to/logfile

Task

A task is dispatched to a task queue at the time (in ms) given by |dispatchTime| attribute of the |Task| object. It is an array because of a runnable can be dispatched and ran for several times.

|begin| is the time that the runnable/task was started to run. |end| is the time where the task finish it's work.

 {'begin': [u'1472463888021'],
  'dispatchTime': [u'1472463888021'],
  'end': [u'1472463888021'],
  'label': [],
  'parent': u'0',
  'process': 22525,
  'sourceEventId': u'0',
  'sourceEventType': u'0',
  'taskId': u'96744138362318',
  'thread': 22525,
  'timeDuration': 0,
  'vptr': '??'},


Load log in python

 import tttools
 profileobject = tttools.loadRawProfile('/abs/to/logfile')

Parent tasks

Parent task of a task is the one create and dispatch the task. You can find the parent task, parent's parent, ... and all ancestors with the following Python instructions.

 taskIdsOfAncestors = profileobject.findAncestors(GivenTaskId)
 import pprint
 pprint.pprint(profileobject.findTasks(taskIdsOfAncestors))

Followers

Followers of a task are tasks that is created by the given task or it's followers.

 taskIdsOfFollowers = profileobject.findFollowers(GivenTaskId)
 import pprint
 pprint.pprint(profileobject.findTasks(taskIdsOfFollowers))

Blocker tasks

You can find what tasks are blocked by the different in time of |dispatchTime| and |begin|.

 tasks = profileobject.findTasks(profileobject.findAncestors(GivenTaskId))
 for task in tasks:
   queuingTIme = long(task.begin[0]) - long(task.dispatchTime[0])
   print 'task: %s, thread: %d, queuingTime: %d' % (task.taskId,
                                                    task.thread,

queuingTime)

The more time a task staying in the queue, the more time the task is blocked by other tasks. You can find what other tasks blocked a task with following instructions.

 task = profileobject.findTask(BlockedTaskId)
 blockerIds =
   profileobject.findTasksStartInTimeThread(int(task.dispatchTime[0]),
                                            int(task.begin[0]),

task.thread)

 blockers = profileobject.findTasks(blockerIds)
 pprint.pprint(blockers)

Labels

You may need to attach some information or strings on tasks and to see strings in the log to help you to identify specific tasks. Following C++ code in Gecko would add a label, i.e. a string, on the current running task of this thread.

 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #endif
 ...
 #ifdef MOZ_TASK_TRACER
 mozilla::tasktracer::AddLabel("Event [%s] ...", str...);
 #endif

Javascript adds labels with a special prefix.

 console.log("#tt# Log message"); // #tt# is the prefix.

For the case of labeling at begin and end of a scope, |AutoScopedLabel| is a helper class to do that.

 {
 #ifdef MOZ_TASK_TRACER
   AutoScopedLabel label("Event [%s] ...", str...);  // label "Begin Event [...]..."
 #endif
   // do something ....
 } // label "End Event [...]..."

The "Begin ..." label would be added when the instance of |AutoScopedLabel| was created. And, "End ..." label would be added when the instance was destroyed.

DESIGN

TaskTracer has 5 types of logs in its log files, DISPATCH, BEGIN, END, VTABLE, and LABEL. They are used to remember

- what the task created and dispatched a new task to
  a target thread,
- the time a task was started to run at the target thread,
- the time a task had done its works,
- the type (vtalbe of the class) of the runnable of a given task, and
- labels that denote what was happened in a task.

TASK ID

Each type of logs has a time stamp to denote when it was happened, and a task ID to uniquely identify a tasks. To make the running code knowning which task is running at a thread, the ID of the running task is stored in the TLS, e.q. thread local storage, when the event loop of the thread starts to run it. That means when a new task was created and dispatched, TaskTracer got the task ID of the running task of current thread from TLS, and denote it as the creator/parent of the new one.

The IDs of a task and its parent task (from TLS) were recorded in a DISPATCH log when it was dispatched to correlates a task and its parent task.

When an IPC message was sent, a new task was created and dispatched at receiving side to handle the message. TaskTracer stores the task ID of the sender of a message in its header, and uses that ID as the parent task ID of the task handling the message at receiving site. With this, TaskTracer correlates tasks over processes.

SOURCE EVENT ID AND TYPE

Not all tasks are always created by another task. For example, a mouse event would create and dispatch a task to handle it, but the mouse event itself is no task. TaskTracer calls mouse events or other events from the kernel as source events. Every source event has an unique ID to identify it, and assign a type to identify whether it is a mouse event, keyboard event, ..., or network event. They are source event IDs and source event types.

The tasks created by source events have no parent task ID, the value of its parent task ID is identical to its task ID. With this rule, users know a task was created for handling a source event if its task ID is identical to its parent task ID.

Source event ID and type would be stored in TLS of threads. They are also retrieved from TLS and stored in the new runnable of a new task when the new task is created/dispatched. When a new task was started to run, the source event ID and type stored on it will be retrieved and stored to TLS too. That means source event ID and type would passing along all tasks created for the source event directly or indirectly. That means they are also dispatched along IPC messages.

VTABLE

For C++, every virtual class, that means a class having at least one virtual method, has a vtab to store entry points of its virtual methods. A VTABLE log contains the address of vtab of the concrete class of an instance of Runnable (a task). With the address of the vtab of a task, TaskTracer can get the concrete class name of the task by symbolicating. People can understand the purpose of a task by its name.