HEX
Server: Apache/2.4.34 (Red Hat) OpenSSL/1.0.2k-fips
System: Linux WORDPRESS 3.10.0-1160.118.1.el7.x86_64 #1 SMP Thu Apr 4 03:33:23 EDT 2024 x86_64
User: digital (1020)
PHP: 7.2.24
Disabled: NONE
Upload Files
File: //opt/perf/examples/arm/armsample3.c
/*****************************************************************************/
/* armsample3    Application Response Measurement sample          FEB01      */
/*                                                                           */
/* This program provides an example of the use of two features of ARM 2.0:   */ 
/* User-Defined Metrics and Correlation.  See the Tracking Your Transactions */
/* and ARM 2.0 API manuals.  Printable copies exist under this product's     */
/* paperdocs directory (for example, /opt/perf/paperdocs/arm/C/).            */
/*                                                                           */
/* For an example of a program which uses User-Defined Metrics but not ARM   */
/* correlators, see the armsample4.c program.                                */
/*                                                                           */
/* This example simulates a client/server application where both server and  */
/* client perform a number of transactions.   Normally application client    */
/* and server components would exist in separate programs, but they're here  */
/* together for simplicity.  The client procedure starts a transaction, and  */
/* requests an ARM correlator from its arm_start call.  This correlator      */
/* is saved by the client and passed to the server so that the server can    */
/* use it when it calls arm_start.  The performance tools running on the     */
/* server can then use this correlator information to distinguish the        */
/* different clients making use of the server.                               */
/*                                                                           */
/* Also shown in this program is the mechanism for passing user-defined      */
/* metric values into the ARM API.  This allows you to not only see the      */
/* response times and service-level information in the performance tools,    */
/* but also data which may be important to the application itself.  For      */ 
/* example, a transaction may be processing different size requests, and     */
/* the size of the request could be a user-defined metric.  When the         */
/* response times are high, this user-defined metric could be used to see    */
/* if long response times correspond to bigger size transaction instances.   */
/*                                                                           */
/* See target platform and compiler for guidelines on 64-bit support.        */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <arm.h>

/* Define macros so sleep works on NT: */
#ifdef _WIN32
#define sleep(n)  Sleep(1000*(n))
#else
#include <netinet/in.h>
#endif

/* Global transaction IDs shared by initialization and other procedures: */
arm_tran_id_t client_tran_id;
arm_tran_id_t server_tran_id;

int pausetime = 5;  /* sleep seconds */
int pausecount = 0;  /* cumulative seconds slept */


/*****************************************************************************/
/*  init_server_application                                                  */
/*                                                                           */
/*  This procedure would be called once by the server program to initialize  */
/*  variables and the ARM API.                                               */
/*****************************************************************************/

void init_server_application(void)
{
    arm_appl_id_t server_appl_id;    /* application id */
    
    /* To use User-Defined Metrics in ARM, you need to create a meta-data */
    /* definition to pass into arm_getid.  This specifies the format of the */
    /* actual UDM data which will later be passed into arm_start and stop. */
    /* Below is one example of a meta-data format.  See the include file */
    /* arm.h for exact definitions.  The ARM 2.0 API guide describes the */
    /* metrics types.  The performance tool metric help documentation */
    /* describes the expected behavior of the Transaction User Measurements */
    /* metrics.         */
    arm_user_data101_t *mbuf_ptr, mbuf = {
        101,
        {0, ARM_AllMetrics_f | ARM_String1_f ,0 ,0},
        {{1,  "1st metric - Type 1 is a COUNTER32"},
         {4,  "2nd metric - Type 4 is a GAUGE32"},
         {5,  "3rd metric - Type 5 is a GAUGE64"},
         {9,  "4th metric - Type 9 is a STRING8"},
         {6,  "5th metric - Type 6 is a GAUGE32/DIVISOR32"},
         {8,  "6th metric - Type 8 is a NUMERICID64"},
         {10, "The last field is always a STRING32        "}
        }};

    arm_data_sz_t        mbuf_sz;   /* size of the meta-data buffer */

    /* Initialize ARM for server: normally arm_init and getid calls */
    /* should only be done once during the initialization block of the */
    /* server program, then repeated transaction instances would be */
    /* done in the main body of the program.  */

    server_appl_id = arm_init("Server_Appl",   /* application name */
                            "*",             /* user-name (default) */
                            0,0,0);          /* reserved: zero */

    /* We do not check the return codes from the ARM API, as normal */
    /* operation of a program should not be affected by whether the ARM */
    /* agent is working. */

    mbuf_ptr = &mbuf;
    mbuf_sz = sizeof(mbuf);

    server_tran_id = arm_getid(server_appl_id,      /* appl_id from arm_init */
                              "Server_tran", /* transaction name */
                              "Transaction in Server program",
                                                    /* tran description */
                              0,                    /* reserved: zero */
                              (arm_data_t *)mbuf_ptr,  /* udm buffer pointer */
                              mbuf_sz);             /* udm buffer size */

    /* Note the ids returned from the ARM API will be invalid if the ARM */
    /* agent is not running (ttd/midaemon) */

    printf("Server transaction ID = %i\n", server_tran_id);

    return;

} /* init_server_application */


/*****************************************************************************/
/* server_application                                                        */
/*                                                                           */
/* This routine is included here to simplify this example.  In a real        */
/* life situation, this piece of code would actually be running in a         */
/* separate program and process on a different system.                       */
/* We are passed an ARM correlator data structure which was returned to      */
/* the client from its arm_start call, and pass it into the server's         */
/* arm_start call.  This will reference the server transaction back to       */
/* the specific client that it is serving.                                   */
/*****************************************************************************/

void server_application(arm_app_correlator_t client_correlator)
{
    /* User data buffer for passing User-Defined Metric values and */
    /* correlator into arm_start, update, and stop */
    arm_user_data1_t     *buf_ptr, buf;
    arm_data_sz_t        buf_sz;

    int                    i, data_len;

    arm_start_handle_t   server_tran_handle = -1;

    /* set up User-Defined Metrics and Correlator buffer */
    buf_ptr = &buf;
    buf_ptr->format = 1;
    buf_ptr->flags[0] = ARM_CorrPar_f;
    buf_ptr->flags[1] = ARM_AllMetrics_f | ARM_String1_f;

    /* Pass the parent correlator received from the client application to    */
    /* the ARM agent using the arm_start call.                               */ 
    /* Note: The correlator is always in network byte order.                 */
    /* It must be converted to host byte order before being accessed.  */
    buf_ptr->correlator.length = client_correlator.length;
    data_len = (ntohs(client_correlator.length) - 
		sizeof(client_correlator.length));
    for (i = 0; i < data_len; i++)
        buf_ptr->correlator.agent_data[i] = client_correlator.agent_data[i]; 

    buf_sz=(sizeof(buf)-sizeof(client_correlator) + 
	    ntohs(client_correlator.length));

    /* the 1st metric will be a counter for sleep time, since counters */
    /* track changes, the value of the derived metric will reflect the */
    /* increment not the total */
    buf_ptr->metric[0].counter32 = pausecount;

    /* the 2nd metric will be a gauge for the sleep time, and as a */
    /* gauge will track the increasing total */
    buf_ptr->metric[1].gauge32 = pausecount;

    /* if the ARM agent defines 64-bit integer fields (long long), then */
    /* we'll stuff a big number in there, else divide into halves */
#ifdef _WIN32
    buf_ptr->metric[2].gauge64 = 444333222111i64;  /* big number >32bitsworth */
#else 
#ifdef ARM_INT64           
    buf_ptr->metric[2].gauge64 = 444333222111LL;  /* big number >32bitsworth */
#else
    buf_ptr->metric[2].gauge64.upper = 1;
    buf_ptr->metric[2].gauge64.lower = 43210;
#endif
#endif

    /* 4th metric, a 8-character string field */
    strcpy(buf_ptr->metric[3].string8, "String 8");

    /* the 5th metric is a floating-point gauge defined by integer */
    /* numerator and denominators */
    buf_ptr->metric[4].gaugedivr32.gauge = 100;
    buf_ptr->metric[4].gaugedivr32.divisor = 3;  /* 100/3 == 33.333... */

    /* the 6th metric is another 64-bit value */
#ifdef _WIN32
    buf_ptr->metric[5].numericid64 = 20000000000i64;
#else 
#ifdef ARM_INT64
    buf_ptr->metric[5].numericid64 = 20000000000LL;
#else
    buf_ptr->metric[5].numericid64.upper = 1;
    buf_ptr->metric[5].numericid64.lower = 43210;
#endif
#endif

    /* the last UDM is a 32-byte string */
    strcpy(buf_ptr->string32,"Initial 32 char string to start ");

    /* both correlator and UDM data are passed in same data buffer */
    server_tran_handle = arm_start(server_tran_id, /* tran_id from arm_getid */
                             0,              /* reserved: 0 */
                             (arm_data_t *)buf_ptr, /* UDM and correlator */
                             buf_sz);               /* data buffer size */
                
    /* This is where the "real work" of the server would be performed */
    /* In this example, we just sleep for "pausetime" seconds */
    sleep(pausetime);
    pausecount += pausetime;

    /* To show use of arm_update, we'll modify some of the User-Defined */
    /* metric fields in the data buffer */
    buf_ptr->metric[4].gaugedivr32.divisor = 4; /* 100/4 == 25 */
#ifdef _WIN32
    buf_ptr->metric[2].gauge64 = -9876543210i64;  /* big negative number */
    buf_ptr->metric[5].numericid64 = 10000000000i64;  /* big num */
#else
#ifdef ARM_INT64
    buf_ptr->metric[2].gauge64 = -9876543210LL;  /* big negative number */
    buf_ptr->metric[5].numericid64 = 10000000000LL;  /* big num */
#endif
#endif
    strcpy(buf_ptr->string32,"This is an UPDATED 32char string");

    arm_update(server_tran_handle,   /* transaction handle from arm_start */
               0,                     /* reserved: zero */
               (arm_data_t *)buf_ptr, /* UDM + Correlator buffer pointer */
               buf_sz);               /* buffer size */
 
    sleep(pausetime);
    pausecount += pausetime;

    /* Change UDM metrics again before stopping transaction instances: */
    buf_ptr->metric[0].counter32 = pausecount;
    buf_ptr->metric[1].gauge32 = pausecount;
    buf_ptr->metric[4].gaugedivr32.gauge = 445; /* 445/4 == 111.25 */
#ifdef _WIN32
    buf_ptr->metric[2].gauge64 = 555444333222i64;  /* more big nums */
    buf_ptr->metric[5].numericid64 = 60000000000i64;
#else
#ifdef ARM_INT64
    buf_ptr->metric[2].gauge64 = 555444333222LL;  /* more big nums */
    buf_ptr->metric[5].numericid64 = 60000000000LL;
#endif
#endif

    arm_stop(server_tran_handle,   /* transaction handle from arm_start */
             ARM_GOOD,              /* successful completion define = 0 */
             0,                     /* reserved: zero */
             (arm_data_t *)buf_ptr, /* data buffer */
             buf_sz);               /* data buffer size */
    
    return;

}    /* server_application() */


/*****************************************************************************/
/*  init_client_application                                                  */
/*                                                                           */
/*  This procedure would be called once by the client program to initialize  */
/*  variables and the ARM API.                                               */
/*****************************************************************************/

void init_client_application(void)
{
    arm_appl_id_t client_appl_id = -1;    /* application id */

    client_appl_id = arm_init("Client_appl", /* application name */
                              "*",           /* default user name */
                              0,0,0);        /* reserved: zero */

    client_tran_id = arm_getid(client_appl_id,   /* appl_id from arm_init */
                              "Client_tran",  /* transaction name */
                              "transaction from client application",
                                              /* tran description */
                              0,              /* reserved: zero */
                              0,0);           /* buffer pointer & size */

    /* Although the ARM API calls may fail if the agent is not running, */
    /* this would not normally impact the runtime behavior of a production */
    /* program.  In this example we'll print the return from getid, which */
    /* will be -1 if ttd is not running */

    printf("Client transaction ID = %i\n", client_tran_id);

    return;

} /* init_client_application */


/*****************************************************************************/
/*  client_transaction                                                       */
/*                                                                           */
/*  This procedure would normally represent the ongoing working section of   */
/*  a client process.  Transactions would be initiated in response to some   */
/*  user activity, then the server would be contacted to process the request */
/*  on behalf of this client.  A client transaction ends when the server     */
/*  completes its action on behalf of the client.                            */
/*****************************************************************************/

void client_transaction(void)
{
    arm_start_handle_t  client_tran_handle = -1;

    arm_user_data1_t    *buf_ptr, buf = {
        1,                           /* Header */
        };

    arm_data_sz_t    buf_sz;

    arm_app_correlator_t   correlator = {
        0,       /* correlator length */
        0,       /* agent data */
        };

    int                    i, data_len, sheep;

    buf_ptr = &buf;
    buf_sz = sizeof(buf);

    /* The client application requests a correlator from the ARM Agent */

    buf_ptr->format = 1;
    buf_ptr->flags[0] = ARM_CorrReq_f;
    client_tran_handle = arm_start(client_tran_id, /*tran_id from arm_getid*/
                                   0,             /* reserved for future use */
                                   (arm_data_t *)buf_ptr, /* metrics buf ptr */
                                   buf_sz);       /* user metric buffer size */

    /* Note no transaction instance handle will be returned if the midaemon */
    /* is not active.  Can use perfstat script to check status of tools  */
    if (client_tran_handle == -1)
      printf("arm_start returned -1, midaemon may be inactive\n");

    /* If the ARM Agent returns a correlator, determine the size of the      */ 
    /* agent specific data in the correlator and pass the data, along with   */
    /* the correlator length, to the server application.                     */
    /* Note: The correlator is always in network byte order.                 */
    /* Its data must be converted to host byte order before being accessed.  */

    if ((buf_ptr->flags[0] & ARM_CorrGen_f) != ARM_CorrGen_f)
        printf("client correlator not being returned\n");
    else {
        correlator.length = buf_ptr->correlator.length;
        data_len = (ntohs(correlator.length) 
		    - sizeof(buf_ptr->correlator.length));
        for (i = 0; i < data_len; i++)
            correlator.agent_data[i] = buf_ptr->correlator.agent_data[i]; 
    }

    /* this is normally where the client-specific processing would take */
    /* place in a real program (possibly both before and after a request */
    /* is sent to the server.  To simulate some activity, we'll count */
    /* ten million sheep both before and after the server request */

    for (sheep = 0; sheep < 10000000; sheep++)  i=sheep;

    server_application(correlator);

    for (sheep = 0; sheep < 10000000; sheep++) i=sheep;

    arm_stop(client_tran_handle, /* transaction handle from arm_start */
             ARM_GOOD,           /* successful completion define = 0 */
             0,                  /* reserved for future use */
             0,0);               /* buffer pointer & buffer size */

    return;

}    /* client_transaction() */



/*****************************************************************************/
/*  Main                                                                     */
/*****************************************************************************/

int
main(void)
{

    init_server_application();

    init_client_application();

    printf("processing transactions...\n");
    /* loop infinitely doing same old boring transaction... what a life */
    while (1) 
        client_transaction();

}