lunes, 6 de octubre de 2014

Detección de memory leaks - Parte III (MTA)

En las entradas anteriores (I y II) vimos como detectar memory leaks en una librería fm, ahora veremos como detectarlas dentro de una aplicación que ha sido desarrollada utilizando el framework MTA de BRM (ésto también sirve para apliaciones que no han sido desarrolladas utilizando MTA, pero el post está orientado a este tipo de aplicaciones).

Para ello utilizaremos otra herramienta: discover.

El objetivo es detectar los memory leaks y la idea es que ademas de detectarlos sepamos en que archivo y en que línea están. Para ello hay que compilar con la opcion -g para ver el código fuente para cada funcion en el stack trace.

En las entradas anteriores se recomendó setear las variables de ambiente LD_PRELOAD y LD_AUDIT en el .profile, Discover no funcionará adecuadamente si éstas 2 variables estan seteadas.

Ejemplo paso a paso: (Código fuente del archivo basic_mta.c y del Makefile al final del post)
  1. Remover las variables de ambiente LD_PRELOAD y LD_AUDIT.
         unset LD_PRELOAD
         unset LD_AUDIT
  2. Compilar utilizando la opción -g (en el Makefile del ejemplo nuestro programa se llamará basic_mta) y si no estamos compilando con gcc usar tambien la opción -O o la opcion -xO[n]
         make clobber all
  3. Instrumenter el binario con discover utilizando las opciones deseadas (discover -? nos mostrará todas las opciones disponibles)
         discover -E 100 -f -m -w resultado.txt -H resultado.html -v basic_mta
  4. Ejecutar nuestro programa normalmente.
         basic_mta
  5. Revisar los archivos generados en busca de errores o memory leaks (en este ejemplo resultado.txt y resultado.html ). Ambos archivos (txt y html) contienen la misma información, por lo que generar ambos es redundante (lo hice a modo de ejemplo), en este ejemplo solo revisaré el arhivo resultado.html.
  6. Abrimos el archivo html y vemos 3 pestañas (Errors, Warnings y Memory leaks).En este ejemplo nos centraremos en la de Memory leaks:

  7. Como se observa en la imagen hay varios memory leaks, al hacer clic en los links se mostrará el stack trace y si se compiló con la opción se puede ver el código fuente de cada función con solo hacer clic en la función:

  8. Ahí se ve el nombre del archivo y la línea donde esta el memory leak.
  9. Para ver el resto de los memory leaks hay que revisar el resto de los links en la solapa Memory leaks.
  10. Para ver más en detalle la explicación de los reportes generados consultar la documentacón oficial de discover.

Observación:

Si al momento de instrumentar el binario nos da un error con las librerías:
    pin> discover -E 100 -f -m -w resultado.txt -H resultado.html -v basic_mta
    discover (info): Sun Memory Error Discovery Tool 2.0 SunOS_sparc 2010/08/13
    discover (info): Prepared binary /export/home/pines/pin14/7.5/lib/libportal.so
    discover (info): Prepared binary /export/home/pines/pin14/martin/memory/mta/basic_mta
    discover (info): Instrumenting target /export/home/pines/pin14/7.5/lib/libportal.so
    discover: error: Cannot accomodate new program headers in the file

Realizar la instrumentación con la opcion -l (lite):
    pin>discover -E 100 -f -m -w resultado.txt -H resultado.html -v -l basic_mta
    discover (info): Sun Memory Error Discovery Tool 2.0 SunOS_sparc 2010/08/13
    discover (info): Prepared binary /export/home/pines/pin14/martin/memory/mta/basic_mta
    discover (info): Instrumenting target /export/home/pines/pin14/martin/memory/mta/basic_mta
    discover (info): Instrumented file output: basic_mta.

Makefile
OS=solaris
VERSION=7.5

##########

PINDIR=${PIN_HOME}
INCDIR=$(PINDIR)/include
LIBDIR=$(PINDIR)/lib

##########
CC_comp_solaris = cc
CC_link_solaris = CC
CC_comp_linux = gcc
CC_link_linux= gcc
CC_comp_hpux_ia64 = cc
CC_link_hpux_ia64 = $(CC_comp_hpux_ia64)
CC_comp_hpux = cc
CC_link_hpux = $(CC_comp_hpux)
CC_comp_aix = xlc_r
CC_link_aix = $(CC_comp_aix)
CC_comp = $(CC_comp_$(OS))
CC_link = $(CC_link_$(OS))

##########
CFLAGS_solaris= -g -xcg92 -O
CFLAGS_linux= -m32 -fPIC -g -pthread
CFLAGS_hpux_ia64= +Z
CFLAGS_hpux= -g -Ae +Z
CFLAGS_aix= -g -Drs6000 -Dunix -D__unix -D__aix
CFLAGS= $(CFLAGS_$(OS))

CPPFLAGS = -I$(INCDIR) 

LDFLAGS_solaris= -R:$(LIBDIR): 
LDFLAGS_linux= -m32 -Wl,--export-dynamic
LDFLAGS_hpux_ia64= -Wl,-E -Wl,+b:$(LIBDIR):
LDFLAGS_hpux= -Wl,-E -Wl,+b:$(LIBDIR):
LDFLAGS_aix=-bM:SRE -bexpall -brtl -lc
LDFLAGS = -L$(LIBDIR) $(LDFLAGS_$(OS))

OS_LIBS_solaris= -lsocket -lnsl -lgen -lposix4 -lpthread -ldl
OS_LIBS_hpux_ia64= -lsec -lrt -lpthread -lCsup -lunwind
OS_LIBS_hpux= -lsec -lrt -lpthread -lCsup
OS_LIBS_aix= -lpthread
OS_LIBS_linux= -lpthread

LDLIBS= -lportal -lmta -lpinsys $(OS_LIBS_$(OS))

##########

INCFILES= $(INCDIR)/pcm.h $(INCDIR)/pin_mta.h $(INCDIR)/pin_bill.h \
   $(INCDIR)/pin_cust.h $(INCDIR)/pin_act.h \
   $(INCDIR)/pin_errs.h $(INCDIR)/pinlog.h

###########

APPS= basic_mta

FILES= basic_mta.c

OBJECTS= basic_mta.o

DEP_linux=$(FILES)
DEP=$(DEP_$(OS))

###########

all: $(APPS) 

clean:
 rm -f $(OBJECTS) core

clobber: clean
 rm -f $(APPS)
 
###########

$(APPS): $(OBJECTS) $(INCFILES) Makefile
 $(CC_link) -o $@ $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJECTS) $(LDLIBS)

$(OBJECTS): $(INCFILES) Makefile $(DEP)
 $(CC_comp) -c $(CFLAGS) $(CPPFLAGS) $(FILES)

###########

FRC:


basic_mta.c
#include <stdio.h>
#include <time.h>
#include "pcm.h"
#include "pin_errs.h"
#include "pinlog.h"
#include "pin_pymt.h"
#include "pin_mta.h"

/*******************************************************************
 * Configuration of application
 * Called prior MTA_CONFIG policy opcode
 *******************************************************************/
PIN_EXPORT void 
pin_mta_config(
 pin_flist_t  *param_flistp,
 pin_flist_t  *app_flistp,
 pin_errbuf_t *ebufp)
{
 int32   mta_flags = 0;
 void   *vp = NULL;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_config parameters flist", param_flistp);
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_config application info flist", app_flistp);
 
 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_FLAGS, 0,ebufp);
 if(vp)
  mta_flags = *((int32*)vp);

 /***********************************************************
 * The new flag MTA_FLAG_VERSION_NEW has been introduced to
 * differentiate between new mta & old mta applications as
 * only new applications have the ability to drop PIN_FLD_PARAMS
 * for valid parameters . It is only for new apps that
 * checking err_params_cnt is valid, otherwise for old applications
 * this check without a distincion for new applications would hamper
 * normal functioning.
 ***********************************************************/
 mta_flags = mta_flags | MTA_FLAG_VERSION_NEW;
 mta_flags = mta_flags | MTA_FLAG_BATCH_MODE;
 
 PIN_FLIST_FLD_SET (app_flistp, PIN_FLD_FLAGS, &mta_flags, ebufp);
 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_config error", ebufp);
 }
}

/*******************************************************************
* Usage information for the specific app.
* Called prior MTA_USAGE policy opcode
*******************************************************************/
PIN_EXPORT void
 pin_mta_usage(
 char *prog)
{
 pin_errbuf_t ebuf;
 pin_flist_t  *ext_flistp = NULL;
 char   *usage_str = NULL;
 char   *format = "\nModo de uso:\t %s\n";
 

 PIN_ERRBUF_CLEAR (&ebuf);
 
 usage_str = (char*)pin_malloc( strlen(format) + strlen(prog) + 1 );

 if (usage_str == NULL) {
  PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_ERROR,"No Memory error");
  return;
 }

 sprintf(usage_str, format ,prog);

 ext_flistp = pin_mta_global_flist_node_get_no_lock(PIN_FLD_EXTENDED_INFO, &ebuf);

 PIN_FLIST_FLD_SET (ext_flistp, PIN_FLD_DESCR, usage_str, &ebuf);
 printf("%s \n", usage_str);
 if (PIN_ERR_IS_ERR(&ebuf)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_usage error", &ebuf);
 }
 
 pin_free(usage_str);
}

/*******************************************************************
 * Application defined search criteria.
 * Called prior MTA_INIT_SEARCH policy opcode
 *******************************************************************/
PIN_EXPORT void
pin_mta_init_search(
 pin_flist_t  *app_flistp,
 pin_flist_t  **s_flistpp,
 pin_errbuf_t *ebufp)
{
 pin_flist_t  *s_flistp = NULL;
 char            *template = "select x from /account where F1 in ('ROOT') ";
 int32   search_flag = 768;
 poid_t   *poid = NULL;
 void   *vp = NULL;
 pin_flist_t  *tmp_flistp = NULL;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_init_search application info flist", app_flistp);

 s_flistp = PIN_FLIST_CREATE(ebufp);
 poid = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_POID_VAL, 0, ebufp);
 PIN_FLIST_FLD_PUT(s_flistp, PIN_FLD_POID, PIN_POID_CREATE(PIN_POID_GET_DB(poid), "/search/pin", -1, ebufp), ebufp);
 PIN_FLIST_FLD_SET (s_flistp, PIN_FLD_FLAGS, &search_flag, ebufp);
 PIN_FLIST_FLD_SET (s_flistp, PIN_FLD_TEMPLATE, template, ebufp);
 tmp_flistp = PIN_FLIST_ELEM_ADD (s_flistp, PIN_FLD_ARGS, 1, ebufp);
 PIN_FLIST_FLD_SET (tmp_flistp, PIN_FLD_ACCOUNT_NO, "", ebufp);

 tmp_flistp = PIN_FLIST_ELEM_ADD (s_flistp, PIN_FLD_RESULTS, 0, ebufp);
 PIN_FLIST_FLD_SET (tmp_flistp, PIN_FLD_ACCOUNT_NO, "", ebufp);

 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_init_search error", ebufp);
  PIN_FLIST_DESTROY_EX (&s_flistp, NULL);
 }else{
  *s_flistpp = s_flistp;
  PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_init_search search flist", s_flistp);
 }
}

/*******************************************************************
 * Search results may be updated, modified or enriched
 * Called prior MTA_TUNE policy opcode
 *******************************************************************/
PIN_EXPORT void 
pin_mta_tune(
 pin_flist_t  *app_flistp,
 pin_flist_t  *srch_res_flistp,
 pin_errbuf_t *ebufp)
{
 pin_const_poid_type_t  type = 0;
 pin_cookie_t    s_cookie = 0;
 pin_cookie_t    m_cookie = 0;
 pin_flist_t     *multi_res_flistp = NULL;
 pin_flist_t     *tmp_flistp = NULL;
 poid_t      *pdp = 0;
 poid_t      *n_pdp = 0;
 int64      db = 0;
 int64      id = 0;
 int32      i = 0;
 int32      s_rec_id = 0;
 int32      m_rec_id = 0;
 void      *vp = 0;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }

 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "basic_mta application info flist", app_flistp);
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "basic_mta search results flist", srch_res_flistp);

 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_OPS_ERROR, MTA_OPTIONAL, ebufp);
 if(vp){
  i = *((int32*)vp);
 }
 
 if (i) {
  while((multi_res_flistp = PIN_FLIST_ELEM_GET_NEXT(srch_res_flistp, PIN_FLD_MULTI_RESULTS, &s_rec_id, 1, &s_cookie, ebufp)) != NULL) {
   m_cookie = 0;
   while((tmp_flistp = PIN_FLIST_ELEM_GET_NEXT(multi_res_flistp, PIN_FLD_RESULTS, &m_rec_id, 1, &m_cookie, ebufp)) != NULL) {
    vp = PIN_FLIST_FLD_TAKE (tmp_flistp, PIN_FLD_POID, 0, ebufp);
    if(vp) {
     pdp = (poid_t*)vp;
     db = PIN_POID_GET_DB (pdp);
     id = PIN_POID_GET_ID (pdp);
     type = PIN_POID_GET_TYPE (pdp);
     id = id * i;
     n_pdp = PIN_POID_CREATE (db, type,id, ebufp);
     PIN_POID_DESTROY (pdp, ebufp);
     PIN_FLIST_FLD_PUT (tmp_flistp, PIN_FLD_POID, n_pdp, ebufp);
    }
   }
  }
 }

 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_tune error", ebufp);
 }
}



/*******************************************************************
 * Function executed at application exit
 * Called prior MTA_EXIT policy opcode
 *******************************************************************/
PIN_EXPORT void
 pin_mta_exit(
 pin_flist_t  *app_flistp,
 pin_errbuf_t *ebufp)
{
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_exit application info flist", app_flistp);
 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_exit error", ebufp);
  printf("Error durante la ejecucion.\n");
 } else {
  printf("Ejecucion exitosa.\n");
 }
}

/*******************************************************************
 * Main application opcode is called here
 *******************************************************************/
PIN_EXPORT void 
pin_mta_worker_opcode(
 pcm_context_t *ctxp,
 pin_flist_t  *srch_res_flistp,
 pin_flist_t  *op_in_flistp,
 pin_flist_t  **op_out_flistpp,
 pin_flist_t  *ti_flistp,
 pin_errbuf_t *ebufp)
{
 pin_cookie_t cookie = NULL;
 pin_flist_t  *app_flistp = NULL;
 int32   rec_id = 0; 
 int32   mta_flags = 0;
 void   *vp = NULL;
 
 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 app_flistp = pin_mta_global_flist_node_get_with_lock (PIN_FLD_APPLICATION_INFO, ebufp);

 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_FLAGS, 0,ebufp);
 if(vp){
  mta_flags = *((int32*)vp);
 }
 
 pin_mta_global_flist_node_release(PIN_FLD_APPLICATION_INFO, ebufp);
 
 //memory leak agregado a proposito
 pin_decimal_t *amount = pbo_decimal_from_double(90, ebufp);
 
 //memory leak agregado a proposito
 poid_t *poid = PIN_POID_CREATE(1, "/account", -1, ebufp);
 
 //memory leak agregado a proposito
 pin_flist_t *tmp_flistp = PIN_FLIST_COPY(op_in_flistp, ebufp);

 //memory leak agregado a proposito
 char *str = (char*)malloc(sizeof(char));
}


Martín Falconi

No hay comentarios.:

Publicar un comentario