Dynamic Probe Class Library

Dynamic Probe Class Library Programming Guide


Chapter 9. Executing probes in target application processes

Chapter 8, Creating probes describes how to define a probe that can execute as part of a target application process. The manor in which the probe is installed and executed within one or more target application processes distinguishes the probe as a particular probe type -- either a point probe, a phase probe, or a one-shot probe.


Installing and activating point probes

Point probes are probes installed at particular locations in the target application code that, when in an activated state, are triggered whenever execution reaches that location in the code. To install and activate a point probe in one or more target application processes, the analysis tool must:

  1. Define the probe as described in Chapter 8, Creating probes.
  2. Navigate the application source structure (represented by SourceObj objects) to identify the instrumentation point (InstPoint object) where the probe will be installed.
  3. Install the probe at the instrumentation point within one or more target application processes.
  4. Activate the probe so that it will execute as part of the target application process whenever execution reaches its installed location in the target application code.

The following steps describe these tasks in greater detail. For sample code, see Example: Installing and activating a point probe.

Step 1: Create point probe

A probe is a probe expression that may optionally call functions. The first step in installing and activating a point probe is to build the actual probe expression that will serve as the point probe. See Chapter 8, Creating probes for detailed instructions on how to do this.

Step 2: Navigate application source structure to get instrumentation point

Instrumentation points (InstPoint objects) are locations within a target application process where an analysis tool can install point probes. Before the analysis tool can install a point probe in a target application process, it must get a reference to the InstPoint object where it wishes to place the probe. To get such a reference, the analysis tool must navigate the target application's source structure by means of source objects (SourceObj objects). Each SourceObj object represents part of the source code structure associated with the target application process, and a group of such objects provide the hierarchical representation of the source code structure which the analysis tool can navigate. For an overview of instrumentation points, see What are instrumentation points?. For an overview of source objects, see What are source objects?.

To navigate an application's source structure to get an instrumentation point, the analysis tool must:

  1. Get a reference to a target application process (Process object) associated with the source code structure to navigate. If the analysis tool is instrumenting a serial application, then this is simply the Process object that represents the target application. If the analysis tool is instrumenting a parallel application, however, this would be just one of the Process class objects managed by the Application class object. Note that while this initial source code navigation must be performed using a single Process object, the analysis tool can later use member functions of the Application class to install, activate, and remove the point probe in all processes managed by the application (assuming these are like processes compiled from the same source as in an SPMD application).
  2. Get a reference to the top-level source object (called the "program object") for the process. The analysis tool does this by calling the Process::get_program_object function.
  3. Navigate one level down into the source hierarchy to get a reference to the source object representing the module where the analysis tool will install the point probe.
  4. Expand the target module source object so the analysis tool can navigate further down into its source hierarchy.
  5. Navigate one level further down into its source hierarchy to get a reference to the source object that represents the function where the analysis tool will install the point probe.
  6. Navigate one level further down into the source hierarchy to get a reference to the instrumentation point where the analysis tool will install the point probe.
Note:For reusable, general-purpose, analysis tools, it is helpful to provide the end user with some way of searching the target application for functions that match a user-supplied search string. The analysis tool can provide this functionality using the SourceObj::bget_function_list function, the SourceObj::get_function_list function, and member functions of the FunctionList and FunctionId classes. After learning the information that follows, refer to Chapter 15, Searching for, and listing, functions in the target application for information on providing a function-searching capability to the analysis tool's end user.

Step 2a: Get target process object

If the analysis tool is instrumenting a serial application, it doesn't need to perform this step, and you can skip ahead to Step 2b: Get program object. If the analysis tool is instrumenting a parallel application, however, it must first get a reference to a single process (Process object) that is managed by the Application class object. This is because a source hierarchy is associated with a particular process only. If multiple processes in the parallel application were compiled from the same source code (such as a SPMD program), the analysis tool can later use member functions of the Application class to install, activate, and remove the point probe for all the Process objects managed by the Application. To navigate the source hierarchy, however, the analysis tool must identify a single representative Process in the Application. To do this, the analysis tool uses the Application::get_process function. The following line of code, for example, returns the first Process object in the Application object app1.

Process p = app1.get_process(0);

For more information on the Application::get_process function, refer to its UNIX man page, or its entry in the DPCL Class Reference.

Step 2b: Get program object

To navigate the source code structure associated with a particular process, the analysis tool first needs to get a reference to the source object (SourceObj object) that represents the top of the process source hierarchy. This top level SourceObj object is called the "program object" and is returned by the Process::get_program_object function. The following line of code stores the program object in a new SourceObj object named myprog.

SourceObj myprog = P.get_program_object();

For more information on the Application::get_program_object function, refer to its UNIX man page, or its entry in the DPCL Class Reference.

Step 2c: Identify target module where point probe will be installed

Once the analysis tool has a reference to the program object, it needs to navigate one level down into the source hierarchy to get a reference to the SourceObj object that represents the module where the analysis tool will install the point probe. To do this, the analysis tool can use the SourceObj::child_count, SourceObj::child, and SourceObj::module_name functions

The SourceObj::child_count function returns the number of child SourceObj objects associated with the SourceObj object; in the case of a program object, these child SourceObj objects represent the program modules. The SourceObj::child function returns a specific child SourceObj. Once it has a reference to the module level SourceObj object, the analysis tool can use the SourceObj::module_name function to identify the name of the module.

This code example uses the SourceObj::child_count function to initialize a for loop, and then, within the for loop, uses the SourceObj::child and SourceObj::module_name functions to identify the target module. This sample code assumes a specialized analysis tool designed for a particular program, and so the name of the target module is already known. For a general-purpose analysis tool, where the target application is not known at design time, these same functions could be used, for example, to populate a scrolled list to show the module names. Here's the specialized analysis tool example that identifies hello.c as the target module.

for (int c = 0; c < myprog.child_count(); c++)

{

   	mymod = myprog.child(c);

 

   	if (strcmp(mymod.module_name(bufmname, bufSize), "hello.c") ==0) 

      {

	       // CODE HERE

      }

}

For more information on the SourceObj::child_count, SourceObj::child, and SourceObj::module_name functions, refer to their UNIX man pages, or their entries in the DPCL Class Reference.

Step 2d: Expand target module

Once the analysis tool identifies the target module source object, it must expand it in order to navigate further down into the source hierarchy. To do this, the analysis tool can use either the blocking function SourceObj::bexpand, or the asynchronous function SourceObj::expand.

Table 47. Expanding a module-level source object
To use: For example:
The blocking function SourceObj::bexpand
for (int c = 0; c < myprog.child_count(); c++)

{

    mymod = myprog.child(c);

 

    if (strcmp(mymod.module_name(bufmname, bufSize), "hello.c") ==0) 

       {

          printf ("found module hello.c. expanding....\n"); 

 

          sts = mymod.bexpand(P);

 

          printf ("expand status  module # %d = %d\n", c, (int)sts);

          if ( (int)sts != 0) printf("%s\n", sts.status_name());

            

          break;

        }

}


The asynchronous function SourceObj::expand
void expand_cb(GCBSysType sys, GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg);

 

// ...

 

for (c = 0; c < myprog.child_count(); c++)

{

    mymod = myprog.child(c);

    name = mymod.module_name(buffer, bufsize);

    if (strcmp(name, "integral_c.c") == 0)

    {

                         // found the target module, expand it

        async_done = 0;

        sts = mymod.expand(P, (GCBFuncType)expand_cb, (GCBTagType)2);

        printf("expand is submitted, status = %d\n", (int)sts);

        if (sts.status() != ASC_success) exit(1);

        break;

    }

}

 

// ...

 

void

expand_cb(GCBSysType sys, GCBTagType tag, GCBTagType obj, GCBMsgType msg)

{

    AisStatus *sts = (AisStatus *)msg;

 

    printf("expand is completed, status = %d\n", (int)*sts);

    async_done = 1;

    Ais_end_main_loop();

}

 


For more information on the SourceObj::bexpand and SourceObj::expand functions, refer to their UNIX man pages, or their entries in the DPCL Class Reference

Step 2e: Identify target function

Once the analysis tool has expanded the target module, it can navigate one more level down into the source hierarchy to get a reference to the SourceObj that represents the function where the analysis tool will install the point probe. Once again, the analysis tool can navigate down into the hierarchy using the SourceObj::child_count and SourceObj::child functions. The SourceObj::child_count function returns the number of child SourceObj objects associated with the SourceObj object; in the case of a module source object, these child SourceObj objects represent the module's functions. The SourceObj::child function returns a specific child SourceObj object. Once it has a reference to the function level SourceObj object, the analysis tool can use the SourceObj::get_demangled_name function (to identify the demangled name of the function) or the SourceObj::get_mangled_name function (to identify the mangled name of the function).

This code example uses the SourceObj::child_count function to initialize a for loop, and then, within the loop, uses SourceObj::child and SourceObj::get_demangled_name functions to identify the target function. This sample code assumes a specialized analysis tool designed for a particular program, and so the name of the target function is already known. For a general purpose analysis tool, where the target application is not known at design time, these same functions could be used, for example, to populate a scrolled list to show the function names. Here's the specialized example that identifies the module hello as the target function.

SourceObj myfun;

 

char      bufdname[bufSize];   // buffer for get_demangled_name(..)

 

printf("function count = %d\n", mymod.child_count());

 

for ( c = 0; c < mymod.child_count(); c++)

{

     myfun = mymod.child(c);

 

     char *name = myfun.get_demangled_name(bufdname, bufSize); 

 

     if (strcmp(name, "hello") ==0)  

     {

	      printf("function hello found.\n");

	      break;

     }

}

For more information on the SourceObj::child_count, SourceObj::child, SourceObj::get_demangled_name, and SourceObj::get_mangled_name functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 2f: Get reference to instrumentation point within target application

Once the analysis tool identifies the target function source object, it can identify the actual instrumentation point (InstPoint object) where it will install the point probe. To do this, the analysis tool can use the SourceObj::exclusive_point_count, SourceObj::exclusive_point, and InstPoint::get_type functions. The SourceObj::exclusive_point_count function returns the number of instrumentation points in the function, and the SourceObj::exclusive_point function returns a specific InstPoint object. The InstPoint::get_type function enables the analysis tool to determine whether the instrumentation point represents a function entry, function exit, or function call site.

This code example uses the SourceObj::exclusive_point_count function to initialize a for loop, and then, within the for loop, uses the SourceObj::exclusive_point and InstPoint::get_type functions to identify the function entry site.

InstPoint  mypoint;

 

printf("point count = %d\n", myfun.exclusive_point_count());

 

for ( c = 0; c < myfun.exclusive_point_count(); c++)

{

     mypoint = myfun.exclusive_point(c);

 

     if ( mypoint.get_type() == IPT_function_entry)

     {

          printf("function entry point found.\n");

          break;

     }

}

For more information on the SourceObj::exclusive_point_count, SourceObj::exclusive_point, and InstPoint::get_type functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 3: Install probe at instrumentation point

Once the analysis tool has defined its probes (as described in Chapter 8, Creating probes) and identified an instrumentation point (as described in Step 2: Navigate application source structure to get instrumentation point), it can install the probe at the instrumentation point. To do this on a single process basis, the analysis tool can use the asynchronous function Process::install_probe or its blocking equivalent Process::binstall_probe. To do this on an application-wide basis, the analysis tool can use the functions Application::install_probe or Application::binstall_probe. Note that all of these functions accept an array of probes. This means that the analysis tool can install multiple point probes using a single call.

Table 48. Installing a point probe in one or more target application processes
To install a probe: In a single process (Process object) In multiple processes (all of the Process objects managed by an Application object)
Using the asynchronous function install_probe
void install_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg);

 

// ...

 

// install the probe in function entry point

points[0] = mypoint;

cbs[0] = data_cb;

tags[0] = (GCBTagType)1;

async_done = 0;

sts = P.install_probe(1, &fullexp, points, 

        cbs, tags, 

        (GCBFuncType)install_probe_cb, 

        (GCBTagType)3, phds);

printf("install_probe is submitted, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// ...

 

void

install_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg)

{

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    printf("task %d install_probe is \

completed, status = %d\n", p->get_task(),

           (int)*sts);

    async_done = 1;

    Ais_end_main_loop();

}

 


void install_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg);

 

// ...

 

// install the probe in function entry point

points[0] = mypoint;

cbs[0] = data_cb;

tags[0] = (GCBTagType)1;

async_done = 0;

sts = A.install_probe(1, &fullexp, points, 

        cbs, tags, (GCBFuncType)install_probe_cb, 

        (GCBTagType)3, phds);

printf("install_probe is submitted, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// ...

 

void

install_probe_cb(GCBSysType sys, GCBTagType tag, 

        GCBTagType obj, GCBMsgType msg)

{

    static int count = 0;

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    printf("task %d install_probe is \

completed, status = %d\n", p->get_task(),

           (int)*sts);

    count++;

    if (count >= num_procs)

    {

        async_done = 1;

        Ais_end_main_loop();

    }

}


Using the blocking function binstall_probe
// install the probe in function entry point

points[0] = mypoint;

cbs[0] = data_cb;

tags[0] = (GCBTagType)1;

sts = P.binstall_probe(1, &fullexp, points, cbs, 

        tags, phds);

printf("install_probe is done, status = %d\n", 

       (int)sts);

if (sts.status() != ASC_success) exit(1);


// install the probe in function entry point

points[0] = mypoint;

cbs[0] = data_cb;

tags[0] = (GCBTagType)1;

sts = A.binstall_probe(1, &fullexp, points, cbs, 

        tags, phds);

printf("install_probe is done, status = %d\n", 

       (int)sts);

if (sts.status() != ASC_success) exit(1);


For more information on the Process::install_probe, Process::binstall_probe, Application::install_probe, or Application::binstall_probe, refer to their UNIX man pages or their entries in the DPCL Class Reference

Step 4: Activate probe

Once you have installed a point probe in one or more target application processes, you must activate it so that it will execute as part of the target application process whenever execution reaches its installed location in the target application code. To do this on a single process basis, the analysis tool can use the asynchronous function Process::activate_probe or its blocking equivalent Process::bactivate_probe. To do this on an application-wide basis (for all Process objects managed by an Application object), the analysis tool can use the function Application::activate_probe or Application::bactivate_probe. Note that all of these functions accept an array of probe handles. This means that the analysis tool can activate more than one point probe using a single call.

Table 49. Activating a point probe in one or more target application processes
To activate a probe: In a single process (Process object) In multiple processes (all of the Process objects managed by an Application object)
Using the asynchronous function activate_probe
void activate_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg);

 

// ...

 

// activate the probe

async_done = 0;

sts = P.activate_probe(1, phds, 

        (GCBFuncType)activate_probe_cb, 

        (GCBTagType)4);

printf("activate_probe is submitted, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// ...

 

void

activate_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg)

{

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    async_done = 1;

    printf("task %d activate_probe is \

completed, status = %d\n", p->get_task(),

           (int)*sts);

    Ais_end_main_loop();

}


void activate_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg);

 

// ...

 

// activate the probe

async_done = 0;

sts = A.activate_probe(1, phds, 

        (GCBFuncType)activate_probe_cb, 

        (GCBTagType)4);

printf("activate_probe is submitted, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// ...

 

void

activate_probe_cb(GCBSysType sys, 

        GCBTagType tag, GCBTagType obj, 

        GCBMsgType msg)

{

    static int count = 0;

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    printf("task %d activate_probe is \

completed, status = %d\n", p->get_task(),

           (int)*sts);

    count++;

    if (count >= num_procs)

    {

        async_done = 1;

        Ais_end_main_loop();

    }

}

 


Using the blocking function bactivate_probe
// activate the probe

sts = P.bactivate_probe(1, phds);

printf("activate_probe is done, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

// enter main loop

Ais_main_loop();

printf("----- The End -----\n");


// activate the probe

sts = A.bactivate_probe(1, phds);

printf("activate_probe is done, \

status = %d\n", (int)sts);

if (sts.status() != ASC_success) exit(1);

// enter main loop

Ais_main_loop();

printf("----- The End -----\n");


For more information on the Process::activate_probe, Process::bactivate_probe, Application::activate_probe, or Application::bactivate_probe functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Example: Installing and activating a point probe

The following example code:

  1. navigates the source structure of a parallel application to identify an instrumentation point.
  2. installs a point probe at the instrumentation point.
  3. activates the point probe.
#include <dpcl.h>

void data_cb   (GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg);

 

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

main(int argc, char *argv[]) 

{

 

    PoeAppl 	A; // A represents a POE application

 

    Ais_initialize();

 

    AisStatus sts = A.binit_procs(argv[1], atoi(argv[2]));  

    printf ("read config status = %d\n", (int)sts);

 

    sts = A.bconnect();  

 

    printf ("connect status = %d\n", (int)sts);

 

    Process  P = A.get_process(0);

 

    SourceObj myprog = P.get_program_object();

 

    SourceObj mymod;

 

    const int   bufSize = 128;

    char        bufmname[bufSize];      // buffer for module_name(..)

 

    for (int c = 0; c < myprog.child_count(); c++)

    {

        mymod = myprog.child(c);

 

        char * modname = mymod.module_name(bufmname,bufSize);

 

        if (strcmp(modname, "chaotic.f") ==0) 

        {

            printf("Module chaotic.f found... expanding\n");

 

            sts = mymod.bexpand(P);

 

            printf ("expand status = %d\n", (int)sts);

 

            break;

        }

    }

 

    SourceObj myfun;

 

    char        bufdname[bufSize];   // buffer for get_demangled_name(..)

 

    for ( c = 0; c < mymod.child_count(); c++)

    {

        myfun = mymod.child(c);

 

        char * funname = myfun.get_demangled_name(bufdname,bufSize);

 

        if (strcmp(funname, "exchange") ==0)  

        {

            printf("function exchange found... \n");

 

            break;

         }

    }

    

    InstPoint  mypoint;

 

    for ( c = 0; c < myfun.exclusive_point_count(); c++)

    {

        mypoint = myfun.exclusive_point(c);

 

        if ( mypoint.get_type() == IPT_function_entry)

        {

            printf("Found function entry point\n");

 

            break;

         }

    }

 

    // malloc pcount;

 

    int	     val = 0;

    ProbeExp pcount = A.balloc_mem( int32_type(), &val, sts);

 

    printf ("malloc  pcount status = %d\n", (int)sts);

 

    ProbeExp addexp = pcount.assign(pcount + ProbeExp(1));

 

  					// Create the expression parameters

    ProbeExp parms[3];

 

    parms[0] = Ais_msg_handle;

    parms[1] = pcount.address();

    parms[2] = ProbeExp (4);

 

    ProbeExp sendexp = Ais_send.call(3,parms);

 

    ProbeExp fullexp = addexp.sequence(sendexp);

 

    ProbeHandle   myph;

    GCBFuncType   cbs[] = {data_cb};

    GCBTagType    tags[] = {(GCBTagType)0};

 

    

    sts = A.binstall_probe(1, &fullexp, &mypoint, 

                           cbs, tags,

                           &myph);

 

    printf ("install status = %d\n",(int)sts);

 

    sts = A.bactivate_probe(1, &myph);

 

    printf ("activate status = %d\n", (int)sts);

 

 

    Ais_main_loop();

}

 

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

void

data_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg)

{

   Process *p = (Process *)obj;

   int *i = (int *)msg;

 

   printf("Task %d sent the count %d\n", p->get_task(),*i); 

 

   // terminate the program after 10 messages are received

 

   if (*i == 10) {

       Ais_end_main_loop();

   }

}

 

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 


Executing phase probes

Phase probes are probes that are executed periodically upon execution of a timer, regardless of what part of the target application's code is executing. The interval at which the probes are executed is measured in CPU time (as opposed to wall-clock time), and is called the phase period. The control mechanism for invoking phase probes at these set CPU-time intervals is called a "phase". Represented by instances of the Phase class, phases enable your analysis tool code to specify the particular phase probe(s) to be invoked and the interval at which their execution is triggered. Note that the DPCL system uses a SIGPROF signal to activate a phase; target applications that themselves use the SIGPROF signal cannot be instrumented with phases. For more information on phase probes and phases, refer to What is a phase probe?.

To add a phase to one or more target application processes in order to have it call its associated phase probes (probe module functions) at set CPU-time intervals, the analysis tool:

  1. Creates one or more probe modules containing the function(s) to be triggered by the phase. A phase can, each time its interval expires, call up to three probe module functions -- a phase begin function, a phase data function, and a phase end function. In addition to these probes module functions that are executed each time the phase is activated, the analysis tool can also create:
  2. If using a data function, allocates and associates data with the phase's data function. Each time the phase is triggered, the data function executes once per datum that the analysis tool has previously allocated and associated with the phase.
  3. For each of the phase probes (probe module functions) to be used by the phase, creates a probe expression that represents a reference to the desired function. This not only includes the phase begin function, phase data function, and phase end function, but also any initialization function or phase exit functions.
  4. Creates a Phase class object that defines the phase probe(s) (probe module function(s)) to be executed by the phase, and the interval between successive invocations of the phase.
  5. Calls a function to add the phase to one or more target application processes. If you want an initialization function to be executed when the phase is first added to the target application process, you supply the function that adds the phase with a probe expression that represents a reference to the initialization function.
  6. Calls a function that specifies up to three exit functions (begin, data, and end) to be executed when the phase is removed from the target application process. You supply this function with probe expressions representing the desired phase exit functions.
  7. If desired, modifies the phase period (the CPU-time interval at which the installed phase is activated to execute its probes).

Step 1: Create probe module(s)

The first step in creating a phase structure to execute phase probes is to create one or more probe modules that contain the functions to be triggered by the phase. A phase can, each time its interval expires, call up to three probe module functions -- a begin function, a data function, and an end function. While the phase must, in order to be useful, call at least one of these functions, any one of them is optional. At the very least, an analysis tool will usually supply a data function.

Once the phase is activated, it will call the phase probe module functions that have been associated with it. The first phase probe it calls is the one identifying the begin function (provided one has been specified). Typically, the begin function will perform any setup tasks that may be required. When the begin function completes, the phase calls the phase probe that identifies the data function (provided one has been specified). The data function executes once per datum that the analysis tool will have previously allocated and associated with this phase. When the data function finishes executing for the last datum, the phase calls the phase probe that identifies the end function (provided one has been specified). Typically, the end function performs any clean up chores that may be required.

In addition to these probes module functions that are executed each time the phase is activated, the analysis tool can also create:

The following example code shows a probe module that defines the phase begin function, the phase data function, and the phase end function. It also defines an initialization function to be executed when the phase is first added to a target application process. In order to execute this module's functions in one or more target application process, the module will need to be compiled and then loaded into the target application process. For more information on how to do this, refer to Creating and calling probe module functions.

#include <stdio.h>

#include <sys/time.h>

#include <sys/param.h>

#include <dpclExt.h>

 

static int	visit = 0;

static char msg[MAXPATHLEN];

static char msg_loc[MAXPATHLEN];

static char msg_time[MAXPATHLEN];

static int 	msg_size;

 

void

init_func(void *handle)

{

   sprintf(msg, "init_func() started\n");

   msg_size = strlen(msg) + 1;

   Ais_send(handle,msg,msg_size) ;

}

 

void

begin_func(void *handle)

{

  int         rc;

 

    sprintf(msg, "begin_func() invoked");

    msg_size = strlen(msg) + 1;

 

    if ((rc = Ais_send(handle, msg, msg_size)) != 0) {

        printf("begin_func(): ERROR, Ais_send()=%d\n", rc);

    }

 

    printf("begin_func() called\n");

}

 

 

 

void

data_func(void *handle, void *_data)

{

    int	rc;

    

    int *data = (int *)_data;

    

    *data = *data + 1;

 

 

    sprintf(msg, "data_func(): data = %d", *data);

    msg_size = strlen(msg) + 1;

 

    if ((rc = Ais_send(handle, msg, msg_size)) != 0) {

         printf("data_func(): ERROR, Ais_send()=%d\n", rc);

    }

    printf("data_func() called\n");

}

 

void

end_func(void *handle)

{

    int		rc;

 

    sprintf(msg, "end_func() invoked\n");

    msg_size = strlen(msg) + 1;

 

    if ((rc = Ais_send(handle, msg, msg_size)) != 0) {

         printf("end_func(): ERROR, Ais_send()=%d\n", rc);

    }

 

    printf("end_func() called\n");

}

Step 2: Create probe expression(s) to reference the probe module function(s)

When creating an instance of the Phase class (as described next in Step 3: Create phase), the analysis tool must, for each phase probe (module function) that the Phase will trigger, create a probe expression that represents a reference to the function. In order to have loaded the probe module into the target application process(es), the analysis tool will have already created a ProbeModule class object to represent the probe module. (For more information, see Creating and calling probe module functions.) To create a probe expression that represents a reference to one of the probe module's functions, the analysis tool can call the Probe_Module::get_reference function. The analysis tool code provides this function with the index of the function within the probe module. To determine the number of functions in the module, the analysis tool can call the ProbeModule::get_count function. To determine the name of a particular function, the analysis tool can call the ProbeModule::get_name function.

This following code example uses the ProbeModule::get_count, ProbeModule::get_name, and ProbeModule::get_reference functions to create probe expressions that represent references to all the probe module functions shown in the example code in Step 1: Create probe module(s). The phase begin function (begin_func), the phase data function (data_func) and the phase end function (end_func) will all be used when instantiating the Phase class in the next step. The initialization function (init_func) is the one to be executed only when the phase is first added to a target application process; the probe expression that represents a reference to this function will be used as a function parameter to the Process::add_phase, Process::badd_phase, Application::add_phase, or Application::badd_phase. These functions are described in Step 4: Add phase to the target application process(es).

                                // look for functions in the loaded module

                                // that are to be used in phase

    for (int j = 0; j < load_mod.get_count(); j++) {

        if (strcmp("init_func", 

           load_mod.get_name(j, buffer, sizeof(buffer))) == 0) 

               {

                 init_func = load_mod.get_reference(j);

               }

        else if (strcmp("begin_func", 

                load_mod.get_name(j, buffer, sizeof(buffer))) == 0) 

                   {

                     begin_func = load_mod.get_reference(j);

                    }

        else if (strcmp("data_func", 

                load_mod.get_name(j, buffer, sizeof(buffer))) == 0) 

                   {

                     data_func = load_mod.get_reference(j);

                    }

        else if (strcmp("end_func", 

                load_mod.get_name(j, buffer, sizeof(buffer))) == 0) 

                   {

                     end_func = load_mod.get_reference(j);

                   }

    }

For more information on the ProbeModule::get_count, ProbeModule::get_name, and ProbeModule::get_reference functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 3: Create phase

A phase structure (Phase class object) defines the phase probe(s) (probe module function(s)) to be executed and the interval between successive invocations of these probes. The Phase class is defined in the header file Phase.h. This following example code creates a phase object that specifies the phase should be activated every second of CPU time to execute the phase begin function (begin_func), the phase data function (data_func) and the phase end function (end_func).

// create a phase with one second period

float period = 1.0;

myphase = Phase(period,

              begin_func, (GCBFuncType)data_cb, (GCBTagType)1,

              data_func, (GCBFuncType)data_cb, (GCBTagType)2,

              end_func, (GCBFuncType)data_cb, (GCBTagType)3);

Although the phase period (the CPU-time interval at which the phase is activated to execute its probes) is initially set when the analysis tool defines the phase, note that the analysis tool can later lengthen or shorted this interval as desired. Refer to Step 7: Modify phase period for more information.

For more information on the Phase class and its constructors, refer to the DPCL Class Reference.

Step 4: Add phase to the target application process(es)

Once the analysis tool has created the Phase object (as described in Step 3: Create phase), it can add it to one or more target application processes. To add a phase on a single process basis, the analysis tool can use the asynchronous function Process::add_phase or its blocking equivalent Process::badd_phase. To add a phase on an application-wide basis (for all Process class objects managed by an Application object), the analysis tool can use the functions Application::add_phase or Application::badd_phase. Optional parameters of these four functions enable you to specify an initialization function to be executed when the phase is added to a target application process, as well as a data callback routine and callback tag for handling message data generated by the initialization function. The following code example uses the Process::badd_phase function to add the phase we created in Step 3: Create phase to a single target application process. The initialization function shown in the probe module in Step 1: Create probe module(s) will execute when the Phase is added to the process. The probe expression init_func represents a reference to the probe module function; we created this probe expression in Step 5: Create probe expression(s) to allocate and associate data with the phase.

// add the phase to application

sts = P.badd_phase(myphase,

          init_func, (GCBFuncType)data_cb, (GCBTagType)4);

if (sts.status()==ASC_success){

   printf("badd_phase() was successful\n");

} else {

   printf("badd_phase() FAILED.. %s\n",sts.status_name());

   exit(0);

}

For more information on the Process::add_phase, Process::badd_phase, Application::add_phase, or Application::badd_phase functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 5: Create probe expression(s) to allocate and associate data with the phase

If using a phase data function, the analysis tool code will need to create a probe expression to allocate and associate data with the phase. Each time the phase is triggered, the data function executes once per datum that the analysis tool has previously allocated and associated with the phase. Executing once per datum enables the data function to perform the same actions on the different data. Each datum, for example, could be a separate counter -- each incremented by the same data function. If the analysis tool does not associate any data with the phase, then the data function will not execute.

Creating probe expressions to represent persistent data describes how you can use the Process::alloc_mem, Process::balloc_mem, Application::alloc_mem, and Application::balloc_mem to allocated memory in target application processes. What this earlier section did not state, however, is the an optional parameter of these functions enables the analysis tool to associate the data allocated in the process(es) with a particular phase. In this following example of the Process::balloc_mem function, the probe expression phase_da is created to represent a persistent integer variable with the initial value of 1000. This probe expression also associates the allocated data with the Phase object myphase created in Step 3: Create phase. Each time this phase is activated, this data value will be passed to the phase data function data_func. Since there is only this one datum associated with the phase, the phase data function will execute only once each time the phase is activated.

// create variable to be used in the phase

int init_value = 1000;

ProbeExp phase_da = P.balloc_mem(int32_type(), (void *)&init_value,

                              myphase, sts);

if (sts.status()==ASC_success){

   printf("balloc_mem() was successful\n");

} else {

   printf("balloc_mem() FAILED.. %s\n",sts.status_name());

   exit(0);

}

For more information on the Process::alloc_mem, Process::balloc_mem, Application::alloc_mem, and Application::balloc_mem functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 6: Specify phase exit functions

If the analysis tool code created one or more phase exit functions in Step 1: Create probe module(s), it needs to associate them with the Phase on one or more target application processes. To do this, the analysis tool code calls the Process::set_phase_exit, Process::bset_phase_exit, Application::set_phase_exit, or Application::bset_phase_exit function. The analysis tool code must supply these functions with probe expressions that represent references to the actual probe module functions. The analysis tool code must, therefore, have already created probe expressions for the exit functions as described in Step 5: Create probe expression(s) to allocate and associate data with the phase. The set_phase_exit and bset_phase_exit functions also allow the analysis tool to specify a callback routine and callback tag for each of the phase exit functions. The following code uses the Process::bset_phase_exit function call to associate a phase exit begin function, a phase exit data function, and a phase exit end function with the Phase object phase1 on one particular target application process. The three phase exit functions are represented by the probe expressions exit_begin_func, exit_data_func, and exit_end_func previously created by calling the ProbeModule::get_reference. The procedure for creating a probe expression using the ProbeModule::get_reference function is described in Step 5: Create probe expression(s) to allocate and associate data with the phase.

sts = P.bset_phase_exit(myphase,

          exit_begin_func, (GCBFuncType)msg_cb, (GCBTagType)6,

          exit_data_func, (GCBFuncType)msg_cb, (GCBTagType)7,

          exit_end_func, (GCBFuncType)msg_cb, (GCBTagType)8);

 

For more information on the Process::set_phase_exit, Process::bset_phase_exit, Application::set_phase_exit, or Application::bset_phase_exit functions, refer to their UNIX man pages or their entries in the DPCL Class Reference.

Step 7: Modify phase period

A phase period specifies the interval of CPU time at which a phase is activated. When the phase is activated, it then executes its phase probes (phase begin, phase data, and phase end functions). The analysis tool initially sets the phase period when defining the Phase class object as described in Step 3: Create phase. The analysis tool can also, once the Phase class object has been added to one or more target application processes, modify the phase period so that the phase is activated at longer or shorter intervals of CPU time. The analysis tool can reset a phase period within a single target application process by calling the Process::set_phase_period function or its blocking equivalent -- Process::bset_phase_period. The analysis tool can also reset a phase period on an application-wide basis (for each Process object managed by an Application object) by calling the Application::set_phase_period or Application::bset_phase_period function.

One use of the Process::set_phase_period, Process::bset_phase_period, Application::set_phase_period, and Application::bset_phase_period functions is to control when a phase will first execute. For example, say you do not want a phase to be activated until after the analysis tool has allocated and associated data with the phase. Unfortunately, you have to add the phase to one or more processes (as described in Step 4: Add phase to the target application process(es)) before you can allocate data for it (as described in Step 5: Create probe expression(s) to allocate and associate data with the phase). In the example code below, the analysis tool adds a phase whose phase period is 999.0 to a particular process. The long phase period effectively places the phase in a suspended state while the analysis tool allocates and associates data with the phase. Once the data allocation step is complete, the analysis tool calls the Process::set_phase_period function to set the phase period to the intended CPU-time interval of 0.1 seconds

                             // create a phase object with a large period

                             // to effectively suspend its execution

    period = 999.0;

    try 

    {

        phase1 = Phase(period,

		       begin_func, (GCBFuncType)msg_cb, (GCBTagType)1,

                       data_func, (GCBFuncType)msg_cb, (GCBTagType)2,

		       end_func, (GCBFuncType)msg_cb, (GCBTagType)3);

    }

    catch (AisStatus excp) 

    {

        printf("new Phase failed with sts=%s\n", excp.status_name());

        exit(1);

    }

                             // add the phase to target application

    sts = P.badd_phase(phase1,

		       init_func, (GCBFuncType)msg_cb, (GCBTagType)4);

    printf("add_phase is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // set the phase's exit functions

    sts = P.bset_phase_exit(phase1,

		            exit_begin_func, (GCBFuncType)msg_cb, (GCBTagType)6,

			    exit_data_func, (GCBFuncType)msg_cb, (GCBTagType)7,

			    exit_end_func, (GCBFuncType)msg_cb, (GCBTagType)8);

    printf("set_phase_exit is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // allocate data variables for the phase

    value = 0;

    pcount = P.balloc_mem(int32_type(), &value, phase1, sts);

    printf("alloc_mem is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

 

    value = 100;

    pcount2 = P.balloc_mem(int32_type(), &value, phase1, sts);

    printf("alloc_mem is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // set the phase to its true execution interval

                             // to resume its normal operation

    period = 0.1;

    sts = P.bset_phase_period(phase1, period);

    printf("set_phase_period is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // query the phase's execution interval

    interval = P.get_phase_period(phase1, sts);

    printf("phase period = %f\n", interval);

In addition to being able to set a phase period, the analysis tool can also ascertain the value of a phase period by calling the Process::get_phase_period function. For more information on the Process::set_phase_period, Process::bset_phase_period, Application::set_phase_period, Application::bset_phase_period, or Process::get_phase_period functions, refer to their UNIX man pages, or their entries in the DPCL Class Reference.

Example: Executing phase probes

The following example code:

  1. Loads a probe module into a target application process.
  2. Creates probe expressions that reference functions in the probe module.
  3. Creates a phase using the probe expressions that represent probe module functions. The phase period is initially set to a high number (999.0) to effectively suspend activation of the phase until data has been allocated for it.
  4. Adds the phase to the target application process.
  5. Allocates data variables for the phase.
  6. Resets the phase period so that the phase is executed every 0.1 second of CPU time.
#include <stdio.h>

#include <stdlib.h>

 

#include <dpcl.h>

 

void msg_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg);

 

void

main(int argc, char *argv[])

{

    Process P;

    AisStatus sts;

    int c;

    int value;

    ProbeExp pcount;

    ProbeExp pcount2;

    ProbeExp init_func;

    ProbeExp begin_func;

    ProbeExp data_func;

    ProbeExp end_func;

    ProbeExp exit_begin_func;

    ProbeExp exit_data_func;

    ProbeExp exit_end_func;

    ProbeModule load_1;

    float period;

    float interval;

    Phase phase1;

    const int bufsize = 256;

    char buffer[bufsize];

    char *name;

 

                             // initialize DPCL environment

    Ais_initialize();

                             // construct a valid Process object

    P = Process(argv[1], atoi(argv[2]));

                             // connect to the target application

    sts = P.bconnect();

    printf("connect is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // load probe module

    load_1 = ProbeModule("./load_1");

    sts = P.bload_module(&load_1);

    printf("load_module is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // look for all the phase related functions

    for (c = 0;c < load_1.get_count(); c++) 

    {

        name = load_1.get_name(c, buffer, bufsize);

        if (strcmp("init_func", name) == 0)

        {

	    init_func = load_1.get_reference(c);

	    printf("found init_func\n");

	}

	else if (strcmp("begin_func", name) == 0)

        {

	    begin_func = load_1.get_reference(c);

	    printf("found begin_func\n");

	}

	else if (strcmp("data_func", name) == 0)

        {

	    data_func = load_1.get_reference(c);

	    printf("found data_func\n");

	}

	else if (strcmp("end_func", name) == 0)

        {

	    end_func = load_1.get_reference(c);

	    printf("found end_func\n");

	}

	else if (strcmp("exit_begin_func", name) == 0)

        {

	    exit_begin_func = load_1.get_reference(c);

	    printf("found exit_begin_func\n");

	}

	else if (strcmp("exit_data_func", name) == 0)

        {

	    exit_data_func = load_1.get_reference(c);

	    printf("found exit_data_func\n");

	}

	else if (strcmp("exit_end_func", name) == 0)

        {

	    exit_end_func = load_1.get_reference(c);

	    printf("found exit_end_func\n");

	}

    }

                             // create a phase object with a large period

                             // to effectively suspend its execution

    period = 999.0;

    try 

    {

        phase1 = Phase(period,

		       begin_func, (GCBFuncType)msg_cb, (GCBTagType)1,

                       data_func, (GCBFuncType)msg_cb, (GCBTagType)2,

		       end_func, (GCBFuncType)msg_cb, (GCBTagType)3);

    }

    catch (AisStatus excp) 

    {

        printf("new Phase failed with sts=%s\n", excp.status_name());

        exit(1);

    }

                             // add the phase to target application

    sts = P.badd_phase(phase1,

		       init_func, (GCBFuncType)msg_cb, (GCBTagType)4);

    printf("add_phase is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // set the phase's exit functions

    sts = P.bset_phase_exit(phase1,

		            exit_begin_func, (GCBFuncType)msg_cb, (GCBTagType)6,

			    exit_data_func, (GCBFuncType)msg_cb, (GCBTagType)7,

			    exit_end_func, (GCBFuncType)msg_cb, (GCBTagType)8);

    printf("set_phase_exit is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // allocate data variables for the phase

    value = 0;

    pcount = P.balloc_mem(int32_type(), &value, phase1, sts);

    printf("alloc_mem is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

 

    value = 100;

    pcount2 = P.balloc_mem(int32_type(), &value, phase1, sts);

    printf("alloc_mem is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // set the phase to its true execution interval

                             // to resume its normal operation

    period = 0.1;

    sts = P.bset_phase_period(phase1, period);

    printf("set_phase_period is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // query the phase's execution interval

    interval = P.get_phase_period(phase1, sts);

    printf("phase period = %f\n", interval);

                             // remove the phase from target application

    sts = P.bremove_phase(phase1);

    printf("remove_phase is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

 

    //Ais_main_loop();

    printf("----- The End -----\n");

}

 

void

msg_cb(GCBSysType sys, GCBTagType tag, GCBTagType obj, GCBMsgType msg)

{

    static int count = 0;

 

    count++;

    char *chp = (char *)msg;

    printf("msg_cb received the msg(%d)=\"", count);

    for (int i = 0; i < sys.msg_size; ++i)

    {

        printf("%c", chp[i]);

    }

    printf("\"\n");

}


Executing one-shot probes

A one-shot probe is a type of probe that is executed by the DPCL system immediately upon request, regardless of what the application happens to be doing. To execute a one-shot probe in one or more target application processes, the analysis tool must:

  1. define the probe as described in Chapter 8, Creating probes.
  2. execute the probe.

Step 1: Create one-shot probe

A probe is a probe expression that may optionally call functions. The first step in executing a one-shot probe is to build the actual probe expression that will serve as the one-shot probe. Since a one-shot probe is executed immediately upon request, regardless of what the target application happens to be doing, your probe expression should be "signal safe".

For detailed instructions on creating probe expressions, refer to Chapter 8, Creating probes.

Step 2: Execute the one-shot probe

Once the analysis tool has defined the probe expression that will serve as the one-shot probe, it can execute it in one or more target application processes. To execute a one-shot probe in a single process, the analysis tool can use the asynchronous function Process::execute or its blocking equivalent Process::bexecute. To execute a one-shot probe on an application-wide basis (for all Process objects managed by an Application object), the analysis tool can use the function Application::execute or Application::bexecute.

Table 50. Executing a one-shot probe in one or more target application processes
To execute a one-shot probe: In a single process (Process object) In multiple processes (all of the Process objects managed by an Application object)
Using the asynchronous function execute_probe
void execute_cb(GCBSysType sys, GCBTagType tag, 

        GCBTagType obj, GCBMsgType msg);

 

// ...

 

addexp = pcount.assign(pcount + ProbeExp(1));

 

// create a probe expression to send the result

// back to DPCL program

parms[0] = Ais_msg_handle;

parms[1] = pcount.address();

parms[2] = ProbeExp(4);

sendexp = Ais_send.call(3, parms);

fullexp = addexp.sequence(sendexp);

 

// issue an one-shot probe

sts = P.execute(fullexp, (GCBFuncType)data_cb, 

        (GCBTagType)1, (GCBFuncType)execute_cb, 

        (GCBTagType)2);

printf("execute is submitted, status = %d\n", 

        (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// enter main loop

Ais_main_loop();

printf("----- The End -----\n");

 

// ...

 

void

execute_cb(GCBSysType sys, GCBTagType tag, 

    GCBTagType obj, GCBMsgType msg)

{

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    printf("task %d execute is completed, \

status = %d\n", p->get_task(),

           (int)*sts);

    Ais_end_main_loop();

}


void execute_cb(GCBSysType sys, GCBTagType tag, 

        GCBTagType obj, GCBMsgType msg);

 

// ...

 

addexp = pcount.assign(pcount + ProbeExp(1));

 

// create a probe expression to send the result

// back to DPCL program

parms[0] = Ais_msg_handle;

parms[1] = pcount.address();

parms[2] = ProbeExp(4);

sendexp = Ais_send.call(3, parms);

fullexp = addexp.sequence(sendexp);

 

// issue an one-shot probe

sts = A.execute(fullexp, (GCBFuncType)data_cb, 

        (GCBTagType)1, (GCBFuncType)execute_cb, 

        (GCBTagType)2);

printf("execute is submitted, status = %d\n", 

       (int)sts);

if (sts.status() != ASC_success) exit(1);

 

// enter main loop

Ais_main_loop();

printf("----- The End -----\n");

 

// ...

 

void

execute_cb(GCBSysType sys, GCBTagType tag, 

        GCBTagType obj, GCBMsgType msg)

{

    static int count = 0;

    Process *p = (Process *)obj;

    AisStatus *sts = (AisStatus *)msg;

 

    count++;

    printf("task %d execute is completed, \

status = %d\n", p->get_task(),

           (int)*sts);

    if (count >= num_procs)

    {

        Ais_end_main_loop();

    }

}


Using the blocking function bexecute_probe
// create an assignment statement

addexp = pcount.assign(pcount + ProbeExp(1));

 

// create a probe expression to send the result

// back to DPCL program

parms[0] = Ais_msg_handle;

parms[1] = pcount.address();

parms[2] = ProbeExp(4);

sendexp = Ais_send.call(3, parms);

fullexp = addexp.sequence(sendexp);

 

// issue an one-shot probe

sts = P.bexecute(fullexp, (GCBFuncType)data_cb, 

        (GCBTagType)1);

printf("execute is done, status = %d\n", 

       (int)sts);

if (sts.status() != ASC_success) exit(1);

 

printf("----- The End -----\n");


// create an assignment statement

addexp = pcount.assign(pcount + ProbeExp(1));

 

// create a probe expression to send the result

// back to DPCL program

parms[0] = Ais_msg_handle;

parms[1] = pcount.address();

parms[2] = ProbeExp(4);

sendexp = Ais_send.call(3, parms);

fullexp = addexp.sequence(sendexp);

 

// issue an one-shot probe

sts = A.bexecute(fullexp, (GCBFuncType)data_cb, 

        (GCBTagType)1);

printf("execute is done, status = %d\n", 

       (int)sts);

if (sts.status() != ASC_success) exit(1);

 

printf("----- The End -----\n");


For more information on the Process::execute, Process::bexecute, Application::execute, and Application::bexecute functions, refer to their UNIX man pages, or their entries in the DPCL Class Reference.

Example: Executing a one-shot probe

The following example code builds a probe expression and executes it as a one-shot probe in a single application process.

#include <stdio.h>

#include <stdlib.h>

 

#include <dpcl.h>

 

void data_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg);

 

void

main(int argc, char *argv[])

{

    Process P;

    AisStatus sts;

    int c;

    int value;

    ProbeExp pcount;

    ProbeExp addexp;

    ProbeExp sendexp;

    ProbeExp fullexp;

    ProbeExp parms[5];

 

                             // initialize DPCL environment

    Ais_initialize();

                             // construct a valid Process object

    P = Process(argv[1], atoi(argv[2]));

                             // connect to the target application

    sts = P.bconnect();

    printf("connect is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // allocate a data variable with init value = 0

    value = 0;

    pcount = P.balloc_mem(int32_type(), &value, sts);

    printf("alloc_mem is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

                             // create an assignment statement

    addexp = pcount.assign(pcount + ProbeExp(1));

                             // create a probe expression to send the result

                             // back to DPCL program

    parms[0] = Ais_msg_handle;

    parms[1] = pcount.address();

    parms[2] = ProbeExp(4);

    sendexp = Ais_send.call(3, parms);

    fullexp = addexp.sequence(sendexp);

                             // issue an one-shot probe

    sts = P.bexecute(fullexp, (GCBFuncType)data_cb, (GCBTagType)1);

    printf("execute is done, status = %d\n", (int)sts);

    if (sts.status() != ASC_success) exit(1);

 

    printf("----- The End -----\n");

}

 

void

data_cb(GCBSysType sys, GCBTagType tag, GCBObjType obj, GCBMsgType msg)

{

    Process *p = (Process *)obj;

    int *i = (int *)msg;

    printf("task %d sent the count %d\n", p->get_task(), *i);

}


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]