Program Structure

It is essential to understand how program structure is defined in order to use the tool correctly.

Programs are written in multiple source files, each containing functions. Each function will contain sequences of statements, loops (e.g. for / while / do), conditionals (e.g. if / switch) and function calls.

Compiling For XTA

The compiler outputs information which allows the XTA tool to make associations between source and instructions. This information is on by default but can be disabled by adding the following flag to the compiler options:

-fno-xta-info

The compiler also supports adding debug information without affecting optimizations. Debug information is not required in order for the XTA tool to analyze code, but the mapping between instructions and source code is not available without the debug information. In order to add debug information compile with:

-g

Structural Nodes

The compiler tools create a binary file with one program per xCORE tile. The XTA tool uses the binary file in order to produce accurate timing results.

When a route is created, the tool analyzes the binary to create a structure which closely represents the high-level program structure. It decomposes the program into structural nodes which can be displayed as a tree.

The worst and best case time is then calculated for each of the structural nodes. The way this is calculated depends on the type of structural node. The worst and best case times for the overall route is built up from the worst and best case times of the sub nodes.

The structural nodes can be of the following types:

  • Instruction: the most basic building block of the program is the instruction.
  • Block: a list of instruction nodes with no conditional branching which is therefore executed in sequence. The worst/best case time for a block is the sum of its component instructions.
  • Sequence: a list of structural nodes which are executed in order. The worst/best case time for a sequence is the sum of the worst/best case times of its sub nodes.
  • Conditional: a set of structural nodes out of which at most one node is executed. If this is within a loop then on each iteration a different node might be chosen. In some cases the entire conditional is optional. In those cases the best case time is for none of the options to be taken. The worst/best case time for a conditional is determined by the worst/best case time of each of its sub nodes.
  • Loop: consists of a header and a body (both of which are structural nodes). The header corresponds to the conditional test part of the loop, and the body corresponds to the code that is executed if the loop is taken. This roughly corresponds to high level code structures such as while or for loops.

    The body is executed once per iteration. The header always executes once more than the number of iterations. The worst/best case times for a loop is the worst/best case time of its header multiplied by (number of iterations + 1) plus the worst/best case time of the body multiplied by the number of iterations.

  • Self-loop: a loop where the header and body are the same. It is therefore considered to have a minimum loop count of 1. This roughly corresponds to high level code structures such as do loops. The worst/best case time for a self-loop is determined by the worst/best case time of its body multiplied up buy the number of iterations.
  • Function: is the high-level construct of the function and consists of a list of other structural nodes. The worst/best case time for a function is calculated in the same way as that of a sequence.

Identifying Nodes: Code References

A code reference is the way to specify a particular location in an application. A code reference is made up of a base and an optional backtrail. The base consists of a reference type and the backtrail consists of a comma separated list of reference types.

There are a number of different reference types, all of which map to one or more instruction program counters (PCs). This will usually be one PC, but can be more than one due to compiler optimizations or because the user has explicitly named multiple instructions with the same reference. Compiler optimizations such as inlining or unrolling will result in the same reference mapping to multiple PCs. For the grammar of specifying a code reference see Code Reference Grammar.

The different reference types are detailed below. The commands to list the instances of them for the currently loaded executable in the console are detailed with each type. In xTIMEcomopser Studio the available references are shown in the Info View.

Source File-Line

Source file-line references are valid for source lines which the compiler has defined as belonging to a source-level basic block. The valid lines can be listed in the console with:

list allsrclabels

Source Label

Source labels are added to source code using the #pragma xta label. To list the source labels in the console type:

list srclabels

Call File-Line

Call file-line references are valid for source lines which map to function calls. To list the valid source lines in the console type:

list allcalls

Call Label

Call labels are added to source code using the #pragma xta call. To list the source labels in the console type:

list calls

Endpoint File-Line

Endpoint file-line references are available for source lines which map to a valid endpoint. To list the endpoints in the console type:

list allendpoints

Endpoint Label

Endpoint labels are added to the source using #pragma xta endpoint. They must be on the line before an input/output operation. To list the labeled endpoints in the console type:

list endpoints

Label

Labels are arbitrary text strings referring to any source or assembly label. To list the labels in the console type:

list labels

Labels in assembly must be within an executable section.

Function

Functions are the functions contained within the binary. To list the labels in the console type:

list functions

Functions in assembler must be labeled as functions with the .type directive in order to be correctly detected by the tool (see xTIMEcomposer Studio User Guide). They must also be within an executable section.

Program Counter (PC)

Program counters are the lowest-level reference, giving a hexadecimal program counter value starting with 0x. They must map to the PC of an instruction within the executable section of the program.

Reference Classes

Particular console commands and GUI actions only work on particular types of references. The sets of reference types that are defined for a particular command is know as a reference classes.

ENDPOINT

These are references which can be used for timing. This means any reference in assembler (PC/label) and only source references which map to lines which can be reliably used for timing. Compiler optimizations cannot remove them or re-order them with respect to each other. In XC code these correspond to source lines with I/O operations. The following console command lists the types available in the class:

help ENDPOINT

CALL

These references map to function calls. These are used in back trails to identify unique instances of a code reference. The following console command lists the types available in the class:

help CALL

FUNCTION

These references map to functions. The following console command lists the types available in the class:

help FUNCTION

LABEL

The following console command lists the types available in the class:

help LABEL

PC

The following console command lists the types available in the class:

help PC

Forcing a Specific Type

It is possible to have a code reference which could map to multiple types. For example there could be an endpoint which has been given the same name as a function in the program. The way a reference in a backtrail is matched can depend upon the type of the reference. In order to resolve this potential ambiguity, it is possible to force the code reference to a certain type by prefixing with its type. See Code Reference Grammar for details.

Back Trails

A code reference’s base may occur multiple times within a program. For example, a function can be called from multiple places. The back trail for a reference is a way of restricting a reference to specific instances. Consider the example file shown in Using backtrails..

Using backtrails.
1  void delay_n_seconds ( int j) {
2      for ( unsigned int i = 0; i < j; ++i) {
3          # pragma xta label " delay_loop "
4          delay_1_second ();
5      }
6  }
7
8  int test () {
9      # pragma xta call " delay_1 "
10     delay_n_seconds (10);
11     # pragma xta call " delay_2 "
12     delay_n_seconds (20);
13     return 0;
14 }

The following commands could be used to time the test function:

  • analyze function test
  • set loop - delay_loop 10

That would have the effect of setting the number of loop iterations for the loop in both instances of the delay_n_seconds to 10. However, as the number of iterations are passed as a parameter to delay_n_seconds, the value is different for each call.

To time test correctly the loop iterations for each instance needs to be specified differently. This can be achieved by the use of the call references and backtrails. For example:

  • analyze function test
  • set loop - delay_1,delay_loop 10
  • set loop - delay_2,delay_loop 20

This tells the tool to set delay_loop to 10 iterations when called from delay_1, and to 20 iterations when called from delay_2. The references used in the above case are composed of a base reference of type source label, and a backtrial or size one, of type call label. The above can also be achieved using the file-line equivalents. For example:

  • analyze function test
  • set loop - source.xc:10,source.xc:3 10
  • set loop - source.xc:12,source.xc:3 20

However, this would not have resulted in a portable and robust script implementation, so using file-line references in this way from a script is not encouraged.

Inlining

When the compiler inlines some code (for example the delay_n_seconds function above) then some references will no longer be valid. In this case the following reference would not exist because the call no longer exists:

source.xc:10,source.xc:3

However, if the call has been labeled with a call label, the compiler ensures that the reference is still valid even if the code is inlined. So, in the above case, the following reference will still be valid;

delay_1,delay_loop

Scope of References

References can have either global or local scope. Globally scoped references are those which apply to (or get resolved on) the global tree. The global tree is the notional structural representation of the whole program, prior to any route analysis taking place. Locally scoped references are those which apply to (or get resolved on) a user created route tree. Whether a particular reference is globally of locally scoped depends on the command being executed. The following commands used globally scoped references:

  • analyze path
  • analyze function
  • analyze loop
  • add exclusion
  • add branch

The following commands used locally scoped references:

  • set/add loop
  • set/add looppath
  • set/add loopscope
  • set/add instructiontime
  • set/add pathtime
  • set/add functiontime

In general, globally scoped references can lead to multiple route creation.

See Also