TOC PREV NEXT INDEX

Using AVS/Express




13 Debugging Objects


This chapter describes techniques for debugging AVS/Express objects. It includes the following sections:

13.1 Debugging Networks

This section describes how to debug a network that does not work, including whether and when methods are firing. After providing general debugging guidelines, it discusses three ways to obtain information about what is happening in a network:

Note that this chapter frequently provides V-code examples and refers to C API routines.

For detailed information on V code, see Chapter 7, V and the V Command Processor.

For information on equivalent C++ API and FORTRAN API routines, see Chapter 9, Object Manager APIs.

For reference descriptions of specific Object Manager API routines, see the AVS/Express on-line help.

General Debugging Guidelines

Many of the general guidelines for debugging applications also apply to debugging AVS/Express networks and methods. They include the following:

Accessing Object Information

Accessing object information involves traversing objects in the network, examining their values and connections. You can access most AVS/Express data through the Network Editor and/or the V Command Processor (VCP).

The following V commands are useful for debugging networks.
Table M-1
V Command
Object information displayed
$int
integer value
$real
real value
$str
string value
$ptr
pointer value
$get_array
array value (useful for small arrays)
$sub_array
array value (useful for large arrays)
$get_array_ref
list of connections to other objects
$refs_to
list of connections from other objects
$array_size
array size
$array_dims
array dimensions
$obj_path
full pathname in the object hierarchy
$obj_val
value (the end of a chain of connections)
$obj_seq
sequence number
$print
current V description

For more information on particular V commands, see Chapter 7, V and the V Command Processor.

Tracing Method Execution

Tracing method execution helps you to determine what methods the Object Manager attempts to execute and in what order. You typically need to trace method execution because one of the following has occurred:

In order to trace method execution, you must set verbose mode:

$set_verbose functions

When it is in verbose mode, AVS/Express displays in the VCP messages returned by the Object Manager when it attempts to execute functions. These messages, called verbose messages, appear in the VCP window. They provide information such as which requests the Object Manager puts into its request queue, which methods it executes, and why it executes them.

To unset verbose mode:

$unset_verbose functions
Required Parameter Value Is Absent or Not Valid

The following example illustrates the verbose messages returned when the Object Manager tries to execute a method with a required parameter whose value is absent or not valid. Suppose that you set verbose mode and then intend to instantiate the module add_num. This module's V definition is as follows:

module add_num {
   float+IPort2+read+req src_1;
   float+IPort2+read+req src_2;
   float+OPort2+write+nonotify res;
   omethod+notify+req+notify_inst update = "USERadd_num";
}

When you instantiate add_num, the Object Manager returns the following verbose messages:

OM:executing:
func   :        SingleWindowApp.add_num.update
arg    :        SingleWindowApp.add_num
events :        object instanced
cause  :        SingleWindowApp.add_num
--- Error detected in: module: OMprim_valid_obj ---
object: Root.Applications.SingleWindowApp.add_num.src_1 does
not have a value
--------------------------------------------------
  OM:is not valid:
  func   :      SingleWindowApp.add_num.update
  arg    :      SingleWindowApp.add_num
  events :      object instanced

The Object Manager reports that the update method of the add_num module is not valid. Here is the reason: the notify_inst attribute is set on the update method for this module, so the Object Manager attempted to execute the method when you instanced it. However, the required input port values were both absent and therefore invalid; therefore, the execution attempt failed.

If you now assign a value to the module's src_1 input port but not to its src_2 input port, the Object Manager again tries to execute the method and again fails. AVS/Express returns the following verbose methods:

OM:executing:
func   :  SingleWindowApp.add_num.update
arg    :  SingleWindowApp.add_num
events :  value changed
cause  :  SingleWindowApp.add_num.src_1
--- Error detected in: module: OMprim_valid_obj ---
object: Root.Applications.SingleWindowApp.add_num.src_2 does
not have a value
--------------------------------------------------
  OM:is not valid:
  func   :  SingleWindowApp.add_num.update
  arg    :  SingleWindowApp.add_num
  events :  value changed

If you now assign a value to the module's src_2 input port, the Object Manager successfully executes the method. AVS/Express returns the following verbose messages:

    OM:executing:
    func   :    SingleWindowApp.add_num.update
    arg    :    SingleWindowApp.add_num
    events :    value changed
    cause  :    SingleWindowApp.add_num.src_2
    done   :    SingleWindowApp.add_num.update

The indentation level of a verbose message indicates the level of nesting of OMpush_ctx/OMpop_ctx routines at the time that the module runs. If the first line of the message is indented by three spaces, the method's execution is being controlled by the explicit use of OMpush_ctx/OMpop_ctx by another running method.

Object Manager Did Not Call Method

You may observe from returned messages that the Object Manager does not call a method when you expect it to. There are a number of reasons why this might happen:

The notify property should be set on a parameter but is not. To verify whether this property is set:

1. In the Network Editor, go to the library containing the module, select the module, and select Object->Object Editor.
2. In the Object Editor, select the parameter and then select Parameters from the Editor option menu.
3. On the Parameter page, inspect the notify check box and check it if necessary.
4. Repeat steps 2 and 3 for each parameter whose notify property you need to check.

A required parameter has not been set. Using the Object Editor in a similar manner, check which parameters are required and ensure that they all have valid values.

No values have changed for those parameters whose notify property has been set.

Expected Output Is Not Produced

If the Object Manager calls your method and, while it apparently executes correctly, you do not see any output, do the following:

If the method is called and its output is set, but you see unexpected output values, you must debug the code that implements the method.

Message for Methods that Return Zero (0) Status

A method returns either one of two values to indicate its execution status:

If a method fails, any methods with a required dependency on the outputs of the method will not be triggered. Consider this simple example:

Figure M-1


If the method for subtract_num fails, the method for add_num is not executed. The verbose messages returned by the Object Manager confirm this:

    OM:executing:
    func   :    SingleWindowApp.subtract_num.update
    arg    :    SingleWindowApp.subtract_num
    events :    value changed
    cause  :    SingleWindowApp.subtract_num.src_1
    --- Error detected in: module: OMprim_valid_obj ---
object: Root.Applications.SingleWindowApp.subtract_num.src_2 does
not have a value
--------------------------------------------------
      OM:is not valid:
      func   :  SingleWindowApp.subtract_num.update
      arg    :  SingleWindowApp.subtract_num
      events :  value changed
    OM:tossing event because required dependency is invalid:
    func   :    SingleWindowApp.add_num.update
    arg    :    SingleWindowApp.add_num
    events :    value changed
    cause  :    SingleWindowApp.subtract_num.update
Tracing Operations on Specific Objects

When debugging, it is often useful to trace the operations that occur on specific objects. For example, if the value of an object is being changed and you do not know which method is responsible, you can trace the set_val operations that occur on that object.

AVS/Express can trace the following operations:

Table M-2
Operation
When operation occurs
set_val
The object's value is changed
get_val
The object's value is accessed
destroy
The object's reference count is decremented
subobj
The object's subobject list is modified
notify
The object's notification list is modified
invoke
The object is executed (applies to method objects only)

By default, AVS/Express traces only set_val operations. You can change the operations that it traces by using the following commands in the VCP:

$set_trace ops_list
$set_trace ops_list

These commands set and unset the trace operation for a specified list of operations.

To trace events on a specific object, set the trace attribute on it.

If you are using a source debugger on the process that is performing the operation, you can set a break point in the function OM_stop_here. This function is called each time that a trace message is printed.

Additional Debugging Routines

A number of additional Object Manager API routines and V commands may be useful in debugging networks. The C API versions are as follows:

Table M-3
Type
Name
Description
C API routine
OMedit_root_object
Opens a VCP window
OMprint_object
Prints an object description to stdout
OMprint_notifies
Prints notifications on an object to stdout
V command
$notify
Reports which functions are invoked on which events, and so forth (analogous to OMprint_notifies)
$refs_to
Reports what objects, if any, refer to a specified object
$deps
Lists dependencies on a method (relevant only when one method reads data and the other writes the same data)
$set_arr_trace
Traces the allocation and deallocation of memory associated with arrays; helpful in finding memory leaks due to the improper use of ARRfree.

For information on equivalent C++ API and FORTRAN API routines, see Chapter 9, Object Manager APIs.

For more information on these V commands, see Testing and Debugging Applications on page 7-41.

13.2 Debugging Modules

You debug a module by using a standard source debugger on the process in which the module runs. You can debug a module running in either the AVS/Express main process or an external process started by the main process.

Before you can use the debugger on the process, you must compile your application so as to produce debuggable symbols. To do this, you specify the appropriate compilation flag as the value of the G make variable, then invoke the express makefile using this value. For most UNIX compilers, the required compilation flag is -g; for Windows compilers, it is usually /Zi or -Zi. (See your debugger documentation for details.)

There are two ways to set the G make variable.

make -f express.mk G=-g
On Windows-based machines, you typically use one of these commands:
make -f express.mk G=/Zi
make -f express.mk G=-Zi
express_install_dir/include/machine_type
Copy the machinc.mk file from this directory into the following directory in your own project:
my_proj/include/machine_type
In the machinc.mk file, the G make variable is set by default to -O. On UNIX machines, you typically change it to the following:
G          =-g
On Windows machines, you typically change it to one of the following:
G          =/Zi    (PC)
G          =-Zi    (PC)

You can now start debugging.

Debugging the Main Process

To debug a module that runs in the AVS/Express main process (typically the express process), simply start your debugger in the normal way on the main process. For example, on an UNIX-based system, you might use a command such as the following:

dbs bin/machine_type/express

For Windows-based machines, you might start Visual C++ and use it to debug the main process.

Once the debugger is running, set break points in the functions defined for your module. When you interrupt the process in this way, AVS/Express catches the interrupt signal and exits cleanly.

Note: On some UNIX platforms, the express process exits improperly when you interrupt and continue in the debugger. A workaround for this problem is to prevent AVS/Express from catching the interrupt signal. To do this, set the environment variable OM_NO_CRASH_HANDLER before you start the debugger on the express process.
Debugging an External Process

An external process is a child process started by the main (typically express) process; for example, a user process. The main process creates a user process when you instantiate an object in the Network Editor's workspace. That object runs in the user process, as do any other objects subsequently instantiated in the same workspace. When you delete the last object in the user process from the workspace, the main process deletes the user process.

For example, suppose that you start the express process and instantiate the add_num module (from the AVS/Express library Library_Workspaces.User_Functions). The express process creates a user process, in which add_num runs. You then instantiate subtract_num (located in the same library), which runs in the same user process as add_num. Now, you delete both subtract_num and add_num. Since the user process now contains no modules, it is no longer needed and is deleted. If you instantiate add_num again, the express process creates a new user process for it.

The following figures provide another example. Suppose that you start an AVS/Express application that contains the following network:

Figure M-1


All of the modules in this network run in the express process. Now, suppose that you instantiate the add_num module in the same workspace.

Figure M-2


The express process creates a user process in which add_num runs. The other modules continue to run in the express process.

If you want to debug a module that runs in an external process, you must attach to that process to use a debugger on it. Note that if you set a break point in the method of a module that runs in an external process, execution will not reach the break point, and the debugger will not break, until the method fires. This, in turn, does not happen until you assign values to all of the module's required parameters. Therefore, even though you attach to a user process, you must ensure that the method fires in order to reach the break point. In the previous example, you must assign values to both the both the src_1 and src_2 parameters before the method fires.

Figure M-3


How you debug an external process varies depending on whether you are running AVS/Express on a UNIX machine or a Windows machine.

Debugging an External Process on a UNIX Machine

On UNIX machines, you debug an AVS/Express external process by using an AVS-supplied script that starts a debugger and facilitates attaching it to the external process. This script, called xp_dbg, resides in the directory express_install_dir/bin. (Because scripts are not machine specific, this file does not need to reside in the machine_type subdirectory.) By default, the xp_dbg script starts the default debugger for your system. You can change this either by editing the script directly or specifying the appropriate command-line option, as noted in the following procedure.

To debug an external process using the xp_dbg script:

1. Ensure that the module was compiled with debuggable symbols (see Debugging Modules on page 13-10).
2. (Optional) Using the editor of your choice, edit the xp_dbg script to specify a debugger other than the default debugger for your system.
3. Create a new terminal window on your machine. The rest of this procedure refers to this window as Terminal 2.
Note: Use Terminal 2 only if a step explicitly instructs you to do so.
4. Delete any modules that are running in the external process to be debugged, so that the process is not active.
5. Determine the name of the external process to be debugged (these processes are stored in the directory express_install_dir/bin/machine_type).
6. In Terminal 2, change your current directory to your AVS/Express project directory and run the xp_dbg script. To start it using the debugger specified in the script, use this command:
xp_dbg bin/machine_type/ext_proc_name
To start it but override the debugger specification in the script, use this command:
xp_dbg -debug debugger_path bin/machine_type/ext_proc_name
The debugger opens and responds with its typical prompt.
7. Set break points as required; for example:
stop in add_num
8. In AVS/Express, instantiate the module that you want to debug. A message like the following appears in Terminal 2:
(dbx)./user instance waiting, fire when ready...
9. Within 15 seconds after this message appears, enter the following debugger command in Terminal 2:
run
Note: If you do not type this command before the wait period times out, AVS/Express stops waiting and executes the process.
10. Build the network necessary to execute the module. When the module's method fires, the debugger stops at the break point.
Debugging an External Process on a Windows Machine

On Windows machines, you use MSDEV, the Visual C++ debugger, to debug an AVS/Express external process. When you start MSDEV, you specify the process ID of the external process on the command line.

To determine the process ID of an external process:

1. Ensure that the external process containing the module to be debugged is running.
2. (Windows NT 4.0 machines) Use the Task Manager to find the process ID as follows:
a. Call up the Task Manager by right-clicking on the Taskbar and selecting the Task Manager option.
b. In the Task Manager, click on the Processes tab.
c. In the Processes page, locate the external process to be debugged and find its process ID in the PID column.
3. (Windows NT machines prior to 4.0) Using the MSDEV pstat command, obtain process statistics about the external process to be debugged. For example:
E:\avs\express>  msdev\bin\winnt\pstat.exe | grep "user.exe"
This command returns output such as the following:
 0:00:00.420   0:00:00.550  2624  75 1032  8 47  2 248 user.exe
pid: f8 pri: 8 Hnd:   47 Pf:    753 Ws:   2624K user.exe
The process number is the number immediately before the first occurrence of the process name; in this example, 248.
Note: If you are debugging a user process, be sure to select the correct user process. Windows NT also uses a process called user.exe; this is not the correct user process.

To debug the external process:

1. Ensure that the module was compiled with debuggable symbols (see Debugging Modules on page 13-10).
2. Start up MSDEV using the following command:
MSDEV -p process_ID
You can run this command from either a command shell or the Desktop (Start->Run on Windows NT 4.0 or Program Manager->File->Run on Windows NT 3.51). If you have already set environment variables, or you need to set them in a command shell, then run MSDEV from the command shell rather than from the Desktop.
Getting Object Information While Debugging Your Module

AVS/Express provides Object Manager API routines that you can call from your debugger to obtain diagnostic information about the state of your objects while your module is executing. This section describes the C API versions; for information on the equivalent C++ API and FORTRAN API routines, see Chapter 9, Object Manager APIs.

Invoking the VCP from the Debugger

While in a debugging session, you can call the OMedit_root_obj routine to bring up the VCP temporarily. When you call this function, the VCP begins by editing the Root object. To exit the VCP and return your debugging session, issue the EOF character (usually Ctrl-d).

If you have a variable that contains OMobj_id, you can bring up the VCP directly on that object by calling the OMedit_obj routine. This feature works only if your debugger allows you to pass arguments to the functions. This function takes a single OMobj_id as an argument.

Printing an Object's Path from the Debugger

To determine the pathname of a variable that contains OMobj_id, call the OMprint_path routine. This routine takes a single OMobj_id argument and prints the pathname of the object passed to the console window.

Problems Passing OMobj_ids as Arguments

Some debuggers do not allow you to pass structures by value as arguments to routines that you call from them. If this is true for your debugger, you cannot call the OMedit_obj and OMprint_path routines directly because each takes an OMobj_id as its first and only argument. Instead, you must call the OMedit_obj_ptr and OMprint_path_ptr routines. These routines each take two arguments that correspond to the elem_id and proc_id fields of OMobj_id. For example:

OMprint_path_ptr(obj_id.elem_id, obj_id.proc_id)
Determining Why a Method Does Not Execute

There are two likely reasons why a method is not called when you change a parameter's value:

The first step in determining the problem is to set verbose mode as described in Tracing Method Execution on page 13-4. In verbose mode, the Object Manager returns a messages that appear in the VCP whenever it attempts to execute a method.

If you change the parameter that should cause your method to execute but you do not see any messages printed, you may not have set notifications properly on the parameter. In the VCP, go to the parameter and use the $notify command on the object.

If AVS/Express tries to run your method but finds an invalid required parameter, use the verbose messages that appear to identify the parameter.

See Required Parameter Value Is Absent or Not Valid on page 13-4.

You can also track down an invalid parameter in the VCP as follows:

1. Go to the module object that contains the method.
2. Use the $valid command on the method object.
3. If the method is not valid, use $valid on each required parameter one at a time until you find the one that is not valid.

For information on $notify and $valid, see Chapter 7, V and the V Command Processor.

Resolving Incorrect Method Execution Order

If you find that two methods are executing in the incorrect order, check the order in which they are defined to run. The method that runs last should be dependent on the method that runs first, not the reverse.

See Controlling Method Execution Order on page 8-13.

To examine the dependencies of a particular method in the VCP, use the $deps command.

For information on $deps, see Chapter 7, V and the V Command Processor.


TOC PREV NEXT INDEX