This C++ example program shows how to use the Start transaction and End transaction APIs to integrate user-defined transaction performance data into Collection Services.
//********************************************************************** // tnstst.C // // This example program illustrates the use // of the Start/End Transaction APIs (qypeStartTransaction, // qypeEndTransaction). // // // This program can be invoked as follows: // CALL lib/TNSTST PARM('threads' 'types' 'transactions' 'delay') // where // threads = number of threads to create (10000 max) // types = number of transaction types for each thread // transactions = number of transactions for each transaction // type // delay = delay time (millisecs) between starting and // ending the transaction // // This program will create "threads" number of threads. Each thread // will generate transactions in the same way. A thread will do // "transactions" number of transactions for each transaction type, // where a transaction is defined as a call to Start Transaction API, // then a delay of "delay" millisecs, then a call to End Transaction // API. Thus, each thread will do a total of "transactions" * "types" // number of transactions. Each transaction type will be named // "TRANSACTION_TYPE_nnn" where nnn ranges from 001 to "types". For // transaction type n, there will be n-1 (16 max) user-provided // counters reported, with counter m reporting m counts for each // transaction. // // This program must be run in a job that allows multiple threads // (interactive jobs typically do not allow multiple threads). One // way to do this is to invoke the program using the SBMJOB command // specifying ALWMLTTHD(*YES). // //********************************************************************** #define _MULTI_THREADED // Includes #include "pthread.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "qusec.h" #include "lbcpynv.h" #include "qypesvpg.h" // Constants #define maxThreads 10000 // Transaction pgm parm structure typedef struct { int types; int trans; int delay; } tnsPgmParm_t; // Error code structure typedef struct { Qus_EC_t error; char Exception_Data[100]; } error_code_t; //********************************************************************** // // Transaction program to run in each secondary thread // //********************************************************************** void *tnsPgm(void *parm) { tnsPgmParm_t *p = (tnsPgmParm_t *)parm; char tnsTyp[] = "TRANSACTION_TYPE_XXX"; char pexData[] = "PEX"; unsigned int pexDataL = sizeof(pexData) - 1; unsigned long long colSrvData[16] = {1,2,3,4,5,6,7,8, 9,10,11,12,13,14,15,16}; unsigned int colSrvDataL; char tnsStrTim[8]; struct timespec ts = {0, 0}; error_code_t errCode; _DPA_Template_T target, source; // Used for LBCPYNV MI instr unsigned int typCnt; unsigned int tnsCnt; int rc; // Initialize error code memset(&errCode, 0, sizeof(errCode)); errCode.error.Bytes_Provided = sizeof(errCode); // Initialize delay time ts.tv_sec = p->delay / 1000; ts.tv_nsec = (p->delay % 1000) * 1000000; // Loop doing transactions for (tnsCnt = 1; tnsCnt <= p->trans; tnsCnt++) { for (typCnt = 1; typCnt <= p->types; typCnt++) { // Set number field in transaction type source.Type = _T_UNSIGNED; source.Length = 4; source.reserved = 0; target.Type = _T_ZONED; target.Length = 3; target.reserved = 0; _LBCPYNV(tnsTyp + 17, &target, &typCnt, &source); // Set Coll Svcs data length in bytes colSrvDataL = (typCnt <= 16) ? (typCnt - 1) : 16; colSrvDataL = colSrvDataL * 8; // Call Start Transaction API qypeStartTransaction(tnsTyp, (unsigned int *)&tnsCnt, pexData, (unsigned int *)&pexDataL, tnsStrTim, &errCode); // Delay specified amount rc = pthread_delay_np(&ts); // Call End Transaction API qypeEndTransaction(tnsTyp, (unsigned int *)&tnsCnt, pexData, (unsigned int *)&pexDataL, tnsStrTim, (unsigned long long *)&colSrvData[0], (unsigned int *)&colSrvDataL, &errCode); } } return NULL; } //********************************************************************** // // Main program to run in primary thread // //********************************************************************** void main(int argc, char *argv[]) { // Integer version of parms int threads; // # of threads int types; // # of types int trans; // # of transactions int delay; // Delay in millisecs pthread_t threadHandle[maxThreads]; tnsPgmParm_t tnsPgmParm; int rc; int i; // Verify 4 parms passed if (argc != 5) { printf("Did not pass 4 parms\n"); return; } // Copy parms into integer variables threads = atoi(argv[1]); types = atoi(argv[2]); trans = atoi(argv[3]); delay = atoi(argv[4]); // Verify parms if (threads > maxThreads) { printf("Too many threads requested\n"); return; } // Initialize transaction pgm parms (do not modify // these while threads are running) tnsPgmParm.types = types; tnsPgmParm.trans = trans; tnsPgmParm.delay = delay; // Create threads that will run transaction pgm for (i=0; i < threads; i++) { // Clear thread handle memset(&threadHandle[i], 0, sizeof(pthread_t)); // Create thread rc = pthread_create(&threadHandle[i], // Thread handle NULL, // Default attributes tnsPgm, // Start routine (void *)&tnsPgmParm); // Start routine parms if (rc != 0) printf("pthread_create() failed, rc = %d\n", rc); } // Wait for each thread to terminate for (i=0; i < threads; i++) { rc=pthread_join(threadHandle[i], // Thread handle NULL); // No exit status } } /* end of Main */