/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * (C) 2013 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #include "mpiimpl.h" int MPIR_T_init_balance = 0; #ifdef MPICH_IS_THREADED MPIU_Thread_mutex_t mpi_t_mutex; int MPIR_T_is_threaded; #endif /* These variables must be initialized in MPI_T_initthread. Especially, * hash table pointers must be initialized to NULL. */ int cat_stamp; UT_array *enum_table; UT_array *cat_table; UT_array *cvar_table; UT_array *pvar_table; name2index_hash_t *cat_hash; name2index_hash_t *cvar_hash; name2index_hash_t *pvar_hashs[MPIR_T_PVAR_CLASS_NUMBER]; /* Create an enum. * IN: enum_name, name of the enum * OUT: handle, handle of the enum */ void MPIR_T_enum_create(const char *enum_name, MPI_T_enum *handle) { MPIR_T_enum_t *e; static const UT_icd enum_item_icd = {sizeof(enum_item_t), NULL, NULL, NULL}; MPIU_Assert(enum_name); MPIU_Assert(handle); utarray_extend_back(enum_table); e = (MPIR_T_enum_t *)utarray_back(enum_table); e->name = MPIU_Strdup(enum_name); MPIU_Assert(e->name); #ifdef HAVE_ERROR_CHECKING e->kind = MPIR_T_ENUM_HANDLE; #endif utarray_new(e->items, &enum_item_icd); (*handle) = e; } /* Add an item to an exisiting enum. * IN: handle, handle to the enum * IN: item_name, name of the item * IN: item_value, value associated with item_name */ void MPIR_T_enum_add_item(MPI_T_enum handle, const char *item_name, int item_value) { enum_item_t *item; MPIU_Assert(handle); MPIU_Assert(item_name); utarray_extend_back(handle->items); item = (enum_item_t *)utarray_back(handle->items); item->name = MPIU_Strdup(item_name); MPIU_Assert(item->name); item->value = item_value; } /* Create a new category with name . * The new category is pushed at the back of cat_table. * Aslo, a new hash entry is added for the category in cat_hash. * Return the newly created category. */ static cat_table_entry_t *MPIR_T_cat_create(const char *cat_name) { int cat_idx; cat_table_entry_t *cat; name2index_hash_t *hash_entry; /* New a category */ utarray_extend_back(cat_table); cat =(cat_table_entry_t *)utarray_back(cat_table); cat->name = MPIU_Strdup(cat_name); cat->desc = NULL; utarray_new(cat->cvar_indices, &ut_int_icd); utarray_new(cat->pvar_indices, &ut_int_icd); utarray_new(cat->subcat_indices, &ut_int_icd); /* Record in cat_hash */ cat_idx = utarray_len(cat_table) - 1; hash_entry = MPIU_Malloc(sizeof(name2index_hash_t)); MPIU_Assert(hash_entry); /* Need not to Strdup cat_name, since cat_table and cat_hash co-exist */ hash_entry->name = cat_name; hash_entry->idx = cat_idx; HASH_ADD_KEYPTR(hh, cat_hash, hash_entry->name, strlen(hash_entry->name), hash_entry); return cat; } /* Add a pvar to an existing or new category * IN: cat_name, name of the category * IN: pvar_index, index of the pvar as defined by MPI_T_pvar_handle_alloc() * If cat_name is NULL or a empty string, nothing happpens. */ int MPIR_T_cat_add_pvar(const char *cat_name, int pvar_index) { int mpi_errno = MPI_SUCCESS; name2index_hash_t *hash_entry; cat_table_entry_t *cat; /* NULL or empty string are allowed */ if (cat_name == NULL || *cat_name == '\0') goto fn_exit; HASH_FIND_STR(cat_hash, cat_name, hash_entry); if (hash_entry != NULL) { /* Found it, i.e., category already exists */ int cat_idx = hash_entry->idx; cat = (cat_table_entry_t *)utarray_eltptr(cat_table, cat_idx); /* FIXME: Is it worth checking duplicated vars? Probably not */ utarray_push_back(cat->pvar_indices, &pvar_index); } else { /* Not found, so create a new category */ cat = MPIR_T_cat_create(cat_name); utarray_push_back(cat->pvar_indices, &pvar_index); /* Notify categories have been changed */ cat_stamp++; } fn_exit: return mpi_errno; fn_fail: goto fn_exit; } /* Add a cvar to an existing or new category * IN: cat_name, name of the category * IN: cvar_index, index of the cvar as defined by MPI_T_cvar_handle_alloc() * If cat_name is NULL or a empty string, nothing happpens. */ int MPIR_T_cat_add_cvar(const char *cat_name, int cvar_index) { int mpi_errno = MPI_SUCCESS; name2index_hash_t *hash_entry; cat_table_entry_t *cat; /* NULL or empty string are allowed */ if (cat_name == NULL || *cat_name == '\0') goto fn_exit; HASH_FIND_STR(cat_hash, cat_name, hash_entry); if (hash_entry != NULL) { /* Found it, i.e., category already exists */ int cat_idx = hash_entry->idx; cat = (cat_table_entry_t *)utarray_eltptr(cat_table, cat_idx); /* FIXME: Is it worth checking duplicated vars? Probably not */ utarray_push_back(cat->cvar_indices, &cvar_index); } else { /* Not found, so create a new category */ cat = MPIR_T_cat_create(cat_name); utarray_push_back(cat->cvar_indices, &cvar_index); /* Notify categories have been changed */ cat_stamp++; } fn_exit: return mpi_errno; fn_fail: goto fn_exit; } /* Add a sub-category to an existing or new category * IN: parent_name, name of the parent category * IN: child_name, name of the child category */ int MPIR_T_cat_add_subcat(const char *parent_name, const char *child_name) { int mpi_errno = MPI_SUCCESS; int parent_index, child_index; name2index_hash_t *hash_entry; cat_table_entry_t *parent; /* NULL or empty string are allowed */ if (parent_name == NULL || *parent_name == '\0' || child_name == NULL || *child_name == '\0') { goto fn_exit; } /* Find or create parent */ HASH_FIND_STR(cat_hash, parent_name, hash_entry); if (hash_entry != NULL) { /* Found parent in cat_table */ parent_index = hash_entry->idx; } else { /* parent is a new category */ MPIR_T_cat_create(parent_name); parent_index = utarray_len(cat_table) - 1; } /* Find or create child */ HASH_FIND_STR(cat_hash, child_name, hash_entry); if (hash_entry != NULL) { /* Found child in cat_table */ child_index = hash_entry->idx; } else { /* child is a new category */ MPIR_T_cat_create(child_name); child_index = utarray_len(cat_table) - 1; } /* Connect parent and child */ parent = (cat_table_entry_t *)utarray_eltptr(cat_table, parent_index); utarray_push_back(parent->subcat_indices, &child_index); /* Notify categories have been changed */ cat_stamp++; fn_exit: return mpi_errno; fn_fail: goto fn_exit; } /* Add description to an existing or new category * IN: cat_name, name of the category * IN: cat_desc, description of the category */ int MPIR_T_cat_add_desc(const char *cat_name, const char *cat_desc) { int cat_idx, mpi_errno = MPI_SUCCESS; name2index_hash_t *hash_entry; cat_table_entry_t *cat; /* NULL args are not allowed */ MPIU_Assert(cat_name); MPIU_Assert(cat_desc); HASH_FIND_STR(cat_hash, cat_name, hash_entry); if (hash_entry != NULL) { /* Found it, i.e., category already exists */ cat_idx = hash_entry->idx; cat = (cat_table_entry_t *)utarray_eltptr(cat_table, cat_idx); MPIU_Assert(cat->desc == NULL); cat->desc = MPIU_Strdup(cat_desc); MPIU_Assert(cat->desc); } else { /* Not found, so create a new category */ cat = MPIR_T_cat_create(cat_name); cat->desc = MPIU_Strdup(cat_desc); MPIU_Assert(cat->desc); /* Notify categories have been changed */ cat_stamp++; } fn_exit: return mpi_errno; fn_fail: goto fn_exit; } /* A low level, generic and internally used interface to register * a cvar to the MPIR_T. * * IN: dtype, MPI datatype for this cvar * IN: name, Name of the cvar * IN: addr, Pointer to the cvar if known at registeration, otherwise NULL. * IN: count, # of elements of this cvar if known at registeration, otherwise 0. * IN: etype, MPI_T_enum or MPI_T_ENUM_NULL * IN: verb, MPI_T_PVAR_VERBOSITY_* * IN: binding, MPI_T_BIND_* * IN: Scope, MPI_T_SCOPE_* * IN: get_addr, If not NULL, it is a callback to get address of the cvar. * IN: get_count, If not NULL, it is a callback to read count of the cvar. * IN: cat, Catogery name of the cvar * IN: desc, Description of the cvar */ void MPIR_T_CVAR_REGISTER_impl( MPI_Datatype dtype, const char* name, const void *addr, int count, MPIR_T_enum_t *etype, MPIR_T_verbosity_t verb, MPIR_T_bind_t binding, MPIR_T_scope_t scope, MPIR_T_cvar_get_addr_cb get_addr, MPIR_T_cvar_get_count_cb get_count, MPIR_T_cvar_value_t defaultval, const char *cat, const char * desc) { name2index_hash_t *hash_entry; cvar_table_entry_t *cvar; int cvar_idx; /* Check whether this is a replicated cvar, whose name is unique. */ HASH_FIND_STR(cvar_hash, name, hash_entry); if (hash_entry != NULL) { /* Found it, the cvar already exists */ cvar_idx = hash_entry->idx; cvar = (cvar_table_entry_t *)utarray_eltptr(cvar_table, cvar_idx); /* Should never override an existing & active var */ MPIU_Assert(cvar->active != TRUE); cvar->active = TRUE; /* FIXME: Do we need to check consistency between the old and new? */ } else { /* Not found, so push the cvar to back of cvar_table */ utarray_extend_back(cvar_table); cvar = (cvar_table_entry_t *)utarray_back(cvar_table); cvar->active = TRUE; cvar->datatype = dtype; cvar->name = MPIU_Strdup(name); MPIU_Assert(cvar->name); if (dtype != MPI_CHAR) { cvar->addr = (void *)addr; } else { cvar->addr = MPIU_Malloc(count); MPIU_Assert(cvar->addr); if (defaultval.str == NULL) { ((char *)(cvar->addr))[0] = '\0'; } else { /* Use greater (>), since count includes the terminating '\0', but strlen does not */ MPIU_Assert(count > strlen(defaultval.str)); strcpy(cvar->addr, defaultval.str); } } cvar->count = count; cvar->verbosity = verb; cvar->bind = binding; cvar->scope = scope; cvar->get_addr = get_addr; cvar->get_count = get_count; cvar->defaultval = defaultval; cvar->desc = MPIU_Strdup(desc); MPIU_Assert(cvar->desc); /* Record in hash table */ cvar_idx = utarray_len(cvar_table) - 1; hash_entry = MPIU_Malloc(sizeof(name2index_hash_t)); MPIU_Assert(hash_entry); /* Need not to Strdup name, since cvar_table and cvar_hash co-exist */ hash_entry->name =name; hash_entry->idx = cvar_idx; HASH_ADD_KEYPTR(hh, cvar_hash, hash_entry->name, strlen(hash_entry->name), hash_entry); /* Add the cvar to a category */ MPIR_T_cat_add_cvar(cat, cvar_idx); } } /* A low level, generic and internally used interface to register * a pvar to MPIR_T. Other modules should use interfaces defined * for concrete pvar classes. * * IN: varclass, MPI_T_PVAR_CLASS_* * IN: dtype, MPI datatype for this pvar * IN: name, Name of the pvar * IN: addr, Pointer to the pvar if known at registeration, otherwise NULL. * IN: count, # of elements of this pvar if known at registeration, otherwise 0. * IN: etype, MPI_T_enum or MPI_T_ENUM_NULL * IN: verb, MPI_T_PVAR_VERBOSITY_* * IN: binding, MPI_T_BIND_* * IN: flags, Bitwise OR of MPIR_T_R_PVAR_FLAGS_{} * IN: get_value, If not NULL, it is a callback to read the pvar. * IN: get_count, If not NULL, it is a callback to read count of the pvar. * IN: cat, Catogery name of the pvar * IN: desc, Description of the pvar */ void MPIR_T_PVAR_REGISTER_impl( int varclass, MPI_Datatype dtype, const char* name, void *addr, int count, MPIR_T_enum_t *etype, int verb, int binding, int flags, MPIR_T_pvar_get_value_cb get_value, MPIR_T_pvar_get_count_cb get_count, const char * cat, const char * desc) { name2index_hash_t *hash_entry; pvar_table_entry_t *pvar; int pvar_idx; int seq = varclass - MPIR_T_PVAR_CLASS_FIRST; /* Check whether this is a replicated pvar, whose name is unique per class */ HASH_FIND_STR(pvar_hashs[seq], name, hash_entry); if (hash_entry != NULL) { /* Found it, the pvar already exists */ pvar_idx = hash_entry->idx; pvar = (pvar_table_entry_t *)utarray_eltptr(pvar_table, pvar_idx); /* Should never override an existing & active var */ MPIU_Assert(pvar->active != TRUE); pvar->active = TRUE; /* FIXME: Do we need to check consistency between the old and new? */ } else { /* Not found, so push the pvar to back of pvar_table */ utarray_extend_back(pvar_table); pvar = (pvar_table_entry_t *)utarray_back(pvar_table); pvar->active = TRUE; pvar->varclass = varclass; pvar->datatype = dtype; pvar->name = MPIU_Strdup(name); MPIU_Assert(pvar->name); pvar->addr = addr; pvar->count = count; pvar->enumtype = etype; pvar->verbosity = verb; pvar->bind = binding; pvar->flags = flags; pvar->get_value = get_value; pvar->get_count = get_count; pvar->desc = MPIU_Strdup(desc); MPIU_Assert(pvar->desc); /* Record in hash table */ pvar_idx = utarray_len(pvar_table) - 1; hash_entry = MPIU_Malloc(sizeof(name2index_hash_t)); MPIU_Assert(hash_entry); /* Need not to Strdup name, since pvar_table and pvar_hashs co-exist */ hash_entry->name = name; hash_entry->idx = pvar_idx; HASH_ADD_KEYPTR(hh, pvar_hashs[seq], hash_entry->name, strlen(hash_entry->name), hash_entry); /* Add the pvar to a category */ MPIR_T_cat_add_pvar(cat, utarray_len(pvar_table)-1); } } /* Implements an MPI_T-style strncpy. Here is the description from the draft * standard: * * Several MPI tool information interface functions return one or more * strings. These functions have two arguments for each string to be returned: * an OUT parameter that identifies a pointer to the buffer in which the * string will be returned, and an IN/OUT parameter to pass the length of the * buffer. The user is responsible for the memory allocation of the buffer and * must pass the size of the buffer (n) as the length argument. Let n be the * length value specified to the function. On return, the function writes at * most n - 1 of the string's characters into the buffer, followed by a null * terminator. If the returned string's length is greater than or equal to n, * the string will be truncated to n - 1 characters. In this case, the length * of the string plus one (for the terminating null character) is returned in * the length argument. If the user passes the null pointer as the buffer * argument or passes 0 as the length argument, the function does not return * the string and only returns the length of the string plus one in the length * argument. If the user passes the null pointer as the length argument, the * buffer argument is ignored and nothing is returned. * * So this routine copies up to (*len)-1 characters from src to dst and then * sets *len to (strlen(dst)+1). If dst==NULL, just return (strlen(src)+1) in * *len. * * This routine does not follow MPICH error handling conventions. */ void MPIR_T_strncpy(char *dst, const char *src, int *len) { /* std. says if len arg is NULL, dst is ignored and nothing is returned (MPI-3, p.563) */ if (len) { /* If dst is NULL or *len is 0, just return src length + 1 */ if (!dst || !*len) { *len = (src == NULL) ? 1 : strlen(src) + 1; } else { /* MPL_strncpy will always terminate the string */ MPIU_Assert(*len > 0); if (src != NULL) { MPL_strncpy(dst, src, *len); *len = (int)strlen(dst) + 1; } else { /* As if an empty string is copied */ *dst = '\0'; *len = 1; } } } }