Blame src/util/mem/handlemem.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
=== BEGIN_MPI_T_CVAR_INFO_BLOCK ===
Packit Service c5cf8c
Packit Service c5cf8c
categories:
Packit Service c5cf8c
    - name        : MEMORY
Packit Service c5cf8c
      description : affects memory allocation and usage, including MPI object handles
Packit Service c5cf8c
Packit Service c5cf8c
cvars:
Packit Service c5cf8c
    - name        : MPIR_CVAR_ABORT_ON_LEAKED_HANDLES
Packit Service c5cf8c
      category    : MEMORY
Packit Service c5cf8c
      type        : boolean
Packit Service c5cf8c
      default     : false
Packit Service c5cf8c
      class       : device
Packit Service c5cf8c
      verbosity   : MPI_T_VERBOSITY_USER_BASIC
Packit Service c5cf8c
      scope       : MPI_T_SCOPE_ALL_EQ
Packit Service c5cf8c
      description : >-
Packit Service c5cf8c
        If true, MPI will call MPI_Abort at MPI_Finalize if any MPI object
Packit Service c5cf8c
        handles have been leaked.  For example, if MPI_Comm_dup is called
Packit Service c5cf8c
        without calling a corresponding MPI_Comm_free.  For uninteresting
Packit Service c5cf8c
        reasons, enabling this option may prevent all known object leaks from
Packit Service c5cf8c
        being reported.  MPICH must have been configure with
Packit Service c5cf8c
        "--enable-g=handlealloc" or better in order for this functionality to
Packit Service c5cf8c
        work.
Packit Service c5cf8c
Packit Service c5cf8c
=== END_MPI_T_CVAR_INFO_BLOCK ===
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* style: allow:printf:5 sig:0 */
Packit Service c5cf8c
#ifdef MPICH_DEBUG_HANDLEALLOC
Packit Service c5cf8c
/* The following is a handler that may be added to finalize to test whether
Packit Service c5cf8c
   handles remain allocated, including those from the direct blocks.
Packit Service c5cf8c
Packit Service c5cf8c
   When adding memory checking, this routine should be invoked as
Packit Service c5cf8c
Packit Service c5cf8c
   MPIR_Add_finalize(MPIR_check_handles_on_finalize, objmem, 1);
Packit Service c5cf8c
Packit Service c5cf8c
   as part of the object intialization.
Packit Service c5cf8c
Packit Service c5cf8c
   The algorithm follows the following approach:
Packit Service c5cf8c
Packit Service c5cf8c
   The memory allocation approach manages a list of available objects.
Packit Service c5cf8c
   These objects are allocated from several places:
Packit Service c5cf8c
      "direct" - this is a block of preallocated space
Packit Service c5cf8c
      "indirect" - this is a block of blocks that are allocated as necessary.
Packit Service c5cf8c
                   E.g., objmem_ptr->indirect[0..objmem_ptr->indirect_size-1]
Packit Service c5cf8c
                   are pointers (or null) to a block of memory.  This block is
Packit Service c5cf8c
                   then divided into objects that are added to the avail list.
Packit Service c5cf8c
Packit Service c5cf8c
   To provide information on the handles that are still in use, we must
Packit Service c5cf8c
   "repatriate" all of the free objects, at least virtually.  To give
Packit Service c5cf8c
   the best information, for each free item, we determine to which block
Packit Service c5cf8c
   it belongs.
Packit Service c5cf8c
*/
Packit Service c5cf8c
int MPIR_check_handles_on_finalize(void *objmem_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Object_alloc_t *objmem = (MPIR_Object_alloc_t *) objmem_ptr;
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
    MPIR_Handle_common *ptr;
Packit Service c5cf8c
    int leaked_handles = FALSE;
Packit Service c5cf8c
    int directSize = objmem->direct_size;
Packit Service c5cf8c
    char *direct = (char *) objmem->direct;
Packit Service c5cf8c
    char *directEnd = (char *) direct + directSize * objmem->size - 1;
Packit Service c5cf8c
    int nDirect = 0;
Packit Service c5cf8c
    int *nIndirect = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Return immediately if this object has not allocated any space */
Packit Service c5cf8c
    if (!objmem->initialized) {
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (objmem->indirect_size > 0) {
Packit Service c5cf8c
        nIndirect = (int *) MPL_calloc(objmem->indirect_size, sizeof(int), MPL_MEM_OBJECT);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* Count the number of items in the avail list.  These include
Packit Service c5cf8c
     * all objects, whether direct or indirect allocation */
Packit Service c5cf8c
    ptr = objmem->avail;
Packit Service c5cf8c
    while (ptr) {
Packit Service c5cf8c
        /* printf("Looking at %p\n", ptr); */
Packit Service c5cf8c
        /* Find where this object belongs */
Packit Service c5cf8c
        if ((char *) ptr >= direct && (char *) ptr < directEnd) {
Packit Service c5cf8c
            nDirect++;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            void **indirect = (void **) objmem->indirect;
Packit Service c5cf8c
            for (i = 0; i < objmem->indirect_size; i++) {
Packit Service c5cf8c
                char *start = indirect[i];
Packit Service c5cf8c
                char *end = start + HANDLE_NUM_INDICES * objmem->size;
Packit Service c5cf8c
                if ((char *) ptr >= start && (char *) ptr < end) {
Packit Service c5cf8c
                    nIndirect[i]++;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (i == objmem->indirect_size) {
Packit Service c5cf8c
                /* Error - could not find the owning memory */
Packit Service c5cf8c
                /* Temp */
Packit Service c5cf8c
                printf("Could not place object at %p in handle memory for type %s\n", ptr,
Packit Service c5cf8c
                       MPIR_Handle_get_kind_str(objmem->kind));
Packit Service c5cf8c
                printf("direct block is [%p,%p]\n", direct, directEnd);
Packit Service c5cf8c
                if (objmem->indirect_size) {
Packit Service c5cf8c
                    printf("indirect block is [%p,%p]\n", indirect[0],
Packit Service c5cf8c
                           (char *) indirect[0] + HANDLE_NUM_INDICES * objmem->size);
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        ptr = ptr->next;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (0) {
Packit Service c5cf8c
        /* Produce a report */
Packit Service c5cf8c
        printf("Object handles:\n\ttype  \t%s\n\tsize  \t%d\n\tdirect size\t%d\n\
Packit Service c5cf8c
\tindirect size\t%d\n", MPIR_Handle_get_kind_str(objmem->kind), objmem->size, objmem->direct_size, objmem->indirect_size);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (nDirect != directSize) {
Packit Service c5cf8c
        leaked_handles = TRUE;
Packit Service c5cf8c
        printf("In direct memory block for handle type %s, %d handles are still allocated\n",
Packit Service c5cf8c
               MPIR_Handle_get_kind_str(objmem->kind), directSize - nDirect);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < objmem->indirect_size; i++) {
Packit Service c5cf8c
        if (nIndirect[i] != HANDLE_NUM_INDICES) {
Packit Service c5cf8c
            leaked_handles = TRUE;
Packit Service c5cf8c
            printf
Packit Service c5cf8c
                ("In indirect memory block %d for handle type %s, %d handles are still allocated\n",
Packit Service c5cf8c
                 i, MPIR_Handle_get_kind_str(objmem->kind), HANDLE_NUM_INDICES - nIndirect[i]);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (nIndirect) {
Packit Service c5cf8c
        MPL_free(nIndirect);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (leaked_handles && MPIR_CVAR_ABORT_ON_LEAKED_HANDLES) {
Packit Service c5cf8c
        /* comm_world has been (or should have been) destroyed by this point,
Packit Service c5cf8c
         * pass comm=NULL */
Packit Service c5cf8c
        MPID_Abort(NULL, MPI_ERR_OTHER, 1, "ERROR: leaked handles detected, aborting");
Packit Service c5cf8c
        MPIR_Assert(0);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return 0;
Packit Service c5cf8c
}
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* returns the name of the handle kind for debugging/logging purposes */
Packit Service c5cf8c
const char *MPIR_Handle_get_kind_str(int kind)
Packit Service c5cf8c
{
Packit Service c5cf8c
#define mpiu_name_case_(name_) case MPIR_##name_: return (#name_)
Packit Service c5cf8c
    switch (kind) {
Packit Service c5cf8c
            mpiu_name_case_(COMM);
Packit Service c5cf8c
            mpiu_name_case_(GROUP);
Packit Service c5cf8c
            mpiu_name_case_(DATATYPE);
Packit Service c5cf8c
            mpiu_name_case_(FILE);
Packit Service c5cf8c
            mpiu_name_case_(ERRHANDLER);
Packit Service c5cf8c
            mpiu_name_case_(OP);
Packit Service c5cf8c
            mpiu_name_case_(INFO);
Packit Service c5cf8c
            mpiu_name_case_(WIN);
Packit Service c5cf8c
            mpiu_name_case_(KEYVAL);
Packit Service c5cf8c
            mpiu_name_case_(ATTR);
Packit Service c5cf8c
            mpiu_name_case_(REQUEST);
Packit Service c5cf8c
            mpiu_name_case_(PROCGROUP);
Packit Service c5cf8c
            mpiu_name_case_(VCONN);
Packit Service c5cf8c
            mpiu_name_case_(WORKQ_ELEM);
Packit Service c5cf8c
            mpiu_name_case_(GREQ_CLASS);
Packit Service c5cf8c
        default:
Packit Service c5cf8c
            return "unknown";
Packit Service c5cf8c
    }
Packit Service c5cf8c
#undef mpiu_name_case_
Packit Service c5cf8c
}