.. _timing_graph_debug_tutorial:

Timing Graph Debugging Tutorial
-------------------------------

When developing VPR or creating/calibrating the timing characteristics of a new architectural model it can be helpful to look 'inside' at VPR's timing graph and analysis results.

.. warning:: This is a very low-level tutorial suitable for power-users and VTR developers

Generating a GraphViz DOT file of the Entire Timing Graph
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

One approach is to have VPR generate a GraphViz DOT file, which visualizes the structure of the timing graph, and the analysis results.
This is enabled by running VPR with :option:`vpr --echo_file` set to ``on``.
This will generate a set of ``.dot`` files in the current directory representing the timing graph, delays, and results of Static Timing Analysis (STA).

.. code-block:: bash

    $ vpr $VTR_ROOT/vtr_flow/arch/timing/EArch.xml $VTR_ROOT/vtr_flow/benchmarks/blif/multiclock/multiclock.blif --echo_file on

    $ ls *.dot
    timing_graph.place_final.echo.dot  timing_graph.place_initial.echo.dot  timing_graph.pre_pack.echo.dot

The ``.dot`` files can then be visualized using a tool like ``xdot`` which draws an interactive version of the timing graph.

.. code-block:: bash

    $ xdot timing_graph.place_final.echo.dot

.. warning:: On all but the smallest designs the full timing graph .dot file is too large to visualize with xdot. See the next section for how to show only a subset of the timing graph.

Which will bring up an interactive visualization of the graph:

.. figure:: multiclock_timing_graph_dot.*

    Full timing graph visualized with xdot on a very small multi-clock circuit.

Where each node in the timing graph is labeled

.. code-block:: none

    Node(X) (TYPE)

Where ``Node(X)`` (e.g. ``Node(3)``) represents the ID of the timing graph node, and ``(TYPE)`` (e.g. ``OPIN``) is the type of node in the graph.

Each node is also annotated with timing information (produced by STA) like

.. code-block:: none

    DATA_ARRIVAL
    Domain(1) to * from Node(16)
    time: 5.2143e-10

    DATA_ARRIVAL
    Domain(2) to * from Node(20)
    time: 6.9184e-10

    DATA_REQUIRED
    Domain(1) to Domain(1) for Node(24)
    time: -2.357e-10

    SLACK
    Domain(1) to Domain(1) for Node(24)
    time: -5.45e-10

where the first line of each entry is the type of timing information (e.g. data arrival time, data required time, slack),
the second line indicates the related launching and capture clocks (with ``*`` acting as a wildcard) and the relevant timing graph node which originated the value,
and the third line is the actual time value (in seconds).

The edges in the timing graph are also annotated with their Edge IDs and delays.
Special edges related to setup/hold (``tsu``, ``thld``) and clock-to-q delays (``tcq``) of sequential elements (e.g. Flip-Flops) are also labeled and drawn with different colors.


Generating a GraphViz DOT file of a subset of the Timing Graph
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For most non-trivial designs the entire timing graph is too large and difficult to visualize.

To assist this you can generate a DOT file for a subset of the timing graph with :option:`vpr --echo_dot_timing_graph_node`

.. code-block:: bash

    $ vpr $VTR_ROOT/vtr_flow/arch/timing/EArch.xml $VTR_ROOT/vtr_flow/benchmarks/blif/multiclock/multiclock.blif --echo_file on --echo_dot_timing_graph_node 23

Running ``xdot timing_graph.place_final.echo.dot`` now shows the only the subset of the timing graph which fans-in or fans-out of the specified node (in this case node ``23``).

.. figure:: multiclock_timing_graph_dot_node_23.*

    Subset of the timing graph which fans in and out of node 23.

Cross-referencing Node IDs with VPR Timing Reports
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The DOT files only label timing graph nodes with their node IDs.
When debugging it is often helpful to correlate these with what are seen in timing reports.

To do this, we need to have VPR generate more detailed timing reports which have additional debug information.
This can be done with :option:`vpr --timing_report_detail` set to ``debug``:

.. code-block:: bash

    $ vpr $VTR_ROOT/vtr_flow/arch/timing/EArch.xml $VTR_ROOT/vtr_flow/benchmarks/blif/multiclock/multiclock.blif --timing_report_detail debug

    $ ls report_timing*
    report_timing.hold.rpt report_timing.setup.rpt

Viewing ``report_timing.setup.rpt``:

.. code-block:: none

    #Path 6
    Startpoint: FFB.Q[0] (.latch at (1,1) tnode(15) clocked by clk2)
    Endpoint  : FFD.D[0] (.latch at (1,1) tnode(25) clocked by clk2)
    Path Type : setup

    Point                                                             Incr      Path
    --------------------------------------------------------------------------------
    clock clk2 (rise edge)                                           0.000     0.000
    clock source latency                                             0.000     0.000
    clk2.inpad[0] (.input at (3,2) tnode(4))                         0.000     0.000
    | (intra 'io' routing)                                           0.042     0.042
    | (inter-block routing:global net)                               0.000     0.042
    | (intra 'clb' routing)                                          0.000     0.042
    FFB.clk[0] (.latch at (1,1) tnode(9))                            0.000     0.042
    | (primitive '.latch' Tcq_max)                                   0.124     0.166
    FFB.Q[0] (.latch at (1,1) tnode(15)) [clock-to-output]           0.000     0.166
    | (intra 'clb' routing)                                          0.120     0.286
    to_FFD.in[1] (.names at (1,1) tnode(21))                         0.000     0.286
    | (primitive '.names' combinational delay)                       0.235     0.521
    to_FFD.out[0] (.names at (1,1) tnode(23))                        0.000     0.521
    | (intra 'clb' routing)                                          0.000     0.521
    FFD.D[0] (.latch at (1,1) tnode(25))                             0.000     0.521
    data arrival time                                                          0.521

    clock clk2 (rise edge)                                           0.000     0.000
    clock source latency                                             0.000     0.000
    clk2.inpad[0] (.input at (3,2) tnode(4))                         0.000     0.000
    | (intra 'io' routing)                                           0.042     0.042
    | (inter-block routing:global net)                               0.000     0.042
    | (intra 'clb' routing)                                          0.000     0.042
    FFD.clk[0] (.latch at (1,1) tnode(8))                            0.000     0.042
    clock uncertainty                                                0.000     0.042
    cell setup time                                                 -0.066    -0.024
    data required time                                                        -0.024
    --------------------------------------------------------------------------------
    data required time                                                        -0.024
    data arrival time                                                         -0.521
    --------------------------------------------------------------------------------
    slack (VIOLATED)                                                          -0.545

We can see that the elements corresponding to specific timing graph nodes are labeled with ``tnode(X)``.
For instance:

.. code-block:: none

    to_FFD.out[0] (.names at (1,1) tnode(23))                        0.000     0.521

shows the netlist pin named ``to_FFD.out[0]`` is ``tnode(23)``, which corresponds to ``Node(23)`` in the DOT file.
