OpenMPI  0.1.1
attribute.c File Reference

Back-end MPI attribute engine. More...

#include "ompi_config.h"
#include "ompi/attribute/attribute.h"
#include "opal/class/opal_bitmap.h"
#include "opal/threads/mutex.h"
#include "opal/util/opal_sos.h"
#include "ompi/constants.h"
#include "ompi/datatype/ompi_datatype.h"
#include "ompi/communicator/communicator.h"
#include "ompi/win/win.h"
#include "ompi/mpi/f77/fint_2_int.h"

Data Structures

struct  attribute_value_t
 

Macros

#define ATTR_TABLE_SIZE   10
 
#define MPI_DATATYPE_NULL_COPY_FN   MPI_TYPE_NULL_COPY_FN
 
#define attr_communicator_f   c_f_to_c_index
 
#define attr_datatype_f   d_f_to_c_index
 
#define attr_win_f   w_f_to_c_index
 
#define CREATE_KEY(key)   opal_bitmap_find_and_set_first_unset_bit(key_bitmap, (key))
 
#define FREE_KEY(key)   opal_bitmap_clear_bit(key_bitmap, (key))
 
#define DELETE_ATTR_CALLBACKS(type, attribute, keyval_obj, object)
 
#define COPY_ATTR_CALLBACKS(type, old_object, keyval_obj, in_attr, new_object, out_attr)
 

Typedefs

typedef enum
ompi_attribute_translate_t 
ompi_attribute_translate_t
 
typedef struct attribute_value_t attribute_value_t
 

Enumerations

enum  ompi_attribute_translate_t { OMPI_ATTRIBUTE_C, OMPI_ATTRIBUTE_FORTRAN_MPI1, OMPI_ATTRIBUTE_FORTRAN_MPI2 }
 

Functions

static void attribute_value_construct (attribute_value_t *item)
 
static void ompi_attribute_keyval_construct (ompi_attribute_keyval_t *keyval)
 
static void ompi_attribute_keyval_destruct (ompi_attribute_keyval_t *keyval)
 
static int set_value (ompi_attribute_type_t type, void *object, opal_hash_table_t **attr_hash, int key, attribute_value_t *new_attr, bool predefined)
 
static int get_value (opal_hash_table_t *attr_hash, int key, attribute_value_t **attribute, int *flag)
 
static void * translate_to_c (attribute_value_t *val)
 
static MPI_Fint translate_to_fortran_mpi1 (attribute_value_t *val)
 
static MPI_Aint translate_to_fortran_mpi2 (attribute_value_t *val)
 
static OBJ_CLASS_INSTANCE (attribute_value_t, opal_object_t, attribute_value_construct, NULL)
 
static OBJ_CLASS_INSTANCE (ompi_attribute_keyval_t, opal_object_t, ompi_attribute_keyval_construct, ompi_attribute_keyval_destruct)
 
int ompi_attr_init (void)
 Initialize the main attribute hash that stores the keyvals and meta data. More...
 
int ompi_attr_finalize (void)
 Destroy the main attribute hash that stores the keyvals and meta data.
 
static int ompi_attr_create_keyval_impl (ompi_attribute_type_t type, ompi_attribute_fn_ptr_union_t copy_attr_fn, ompi_attribute_fn_ptr_union_t delete_attr_fn, int *key, ompi_attribute_fortran_ptr_t *extra_state, int flags, void *bindings_extra_state)
 
int ompi_attr_create_keyval (ompi_attribute_type_t type, ompi_attribute_fn_ptr_union_t copy_attr_fn, ompi_attribute_fn_ptr_union_t delete_attr_fn, int *key, void *extra_state, int flags, void *bindings_extra_state)
 Create a new key for use by attribute of Comm/Win/Datatype. More...
 
int ompi_attr_create_keyval_fint (ompi_attribute_type_t type, ompi_attribute_fn_ptr_union_t copy_attr_fn, ompi_attribute_fn_ptr_union_t delete_attr_fn, int *key, MPI_Fint extra_state, int flags, void *bindings_extra_state)
 Same as ompi_attr_create_keyval, but extra_state is a Fortran default integer.
 
int ompi_attr_create_keyval_aint (ompi_attribute_type_t type, ompi_attribute_fn_ptr_union_t copy_attr_fn, ompi_attribute_fn_ptr_union_t delete_attr_fn, int *key, MPI_Aint extra_state, int flags, void *bindings_extra_state)
 Same as ompi_attr_create_keyval, but extra_state is a Fortran address integer.
 
int ompi_attr_free_keyval (ompi_attribute_type_t type, int *key, bool predefined)
 Free an attribute keyval. More...
 
int ompi_attr_delete (ompi_attribute_type_t type, void *object, opal_hash_table_t *attr_hash, int key, bool predefined)
 Delete an attribute on the comm/win/datatype. More...
 
int ompi_attr_set_c (ompi_attribute_type_t type, void *object, opal_hash_table_t **attr_hash, int key, void *attribute, bool predefined)
 Set an attribute on the comm/win/datatype in a form valid for C. More...
 
int ompi_attr_set_fortran_mpi1 (ompi_attribute_type_t type, void *object, opal_hash_table_t **attr_hash, int key, MPI_Fint attribute, bool predefined)
 Set an attribute on the comm/win/datatype in a form valid for Fortran MPI-1. More...
 
int ompi_attr_set_fortran_mpi2 (ompi_attribute_type_t type, void *object, opal_hash_table_t **attr_hash, int key, MPI_Aint attribute, bool predefined)
 Set an attribute on the comm/win/datatype in a form valid for Fortran MPI-2. More...
 
int ompi_attr_get_c (opal_hash_table_t *attr_hash, int key, void **attribute, int *flag)
 Get an attribute on the comm/win/datatype in a form valid for C. More...
 
int ompi_attr_get_fortran_mpi1 (opal_hash_table_t *attr_hash, int key, MPI_Fint *attribute, int *flag)
 Get an attribute on the comm/win/datatype in a form valid for Fortran MPI-1. More...
 
int ompi_attr_get_fortran_mpi2 (opal_hash_table_t *attr_hash, int key, MPI_Aint *attribute, int *flag)
 Get an attribute on the comm/win/datatype in a form valid for Fortran MPI-2. More...
 
int ompi_attr_copy_all (ompi_attribute_type_t type, void *old_object, void *new_object, opal_hash_table_t *oldattr_hash, opal_hash_table_t *newattr_hash)
 This to be used from functions like MPI_*_DUP inorder to copy all the attributes from the old Comm/Win/Dtype object to a new object. More...
 
int ompi_attr_delete_all (ompi_attribute_type_t type, void *object, opal_hash_table_t *attr_hash)
 This to be used to delete all the attributes from the Comm/Win/Dtype object in one shot. More...
 

Variables

static opal_hash_table_tkeyval_hash
 
static opal_bitmap_tkey_bitmap
 
static unsigned int int_pos = 12345
 
static opal_mutex_t keyval_hash_lock
 
static opal_mutex_t attr_hash_lock
 

Detailed Description

Back-end MPI attribute engine.

This is complicated enough that it deserves a lengthy discussion of what is happening. This is extremely complicated stuff, paired with the fact that it is not described well in the MPI standard. There are several places in the standard that should be read about attributes:

MPI-1: Section 5.7 (pp 167-173) MPI-1: Section 7.1 (pp 191-192) predefined attributes in MPI-1 MPI-2: Section 4.12.7 (pp 57-59) interlanguage attribute clarifications MPI-2: Section 6.2.2 (pp 112) window predefined attributes MPI-2: Section 8.8 (pp 198-208) new attribute caching functions

After reading all of this, note the following:

  • C MPI-1 and MPI-2 attribute functions and functionality are identical except for their function names.
  • Fortran MPI-1 and MPI-2 attribute functions and functionality are different (namely: the parameters are different sizes, both in the functions and the user callbacks, and the assignments to the different sized types occur differently [e.g., truncation and sign extension])
  • C functions store values by reference (i.e., writing an attribute means writing a pointer to an instance of something; changing the value of that instance will make it visible to anyone who reads that attribute value).
  • Fortran functions store values by value (i.e., writing an attribute value means that anyone who reads that attribute value will not be able to affect the value read by anyone else).
  • The predefined attribute MPI_WIN_BASE seems to flaunt the rules designated by the rest of the standard; it is handled specifically in the MPI_WIN_GET_ATTR binding functions (see the comments in there for an explanation).
  • MPI-2 4.12.7:Example 4.13 (p58) is wrong. The C->Fortran example should have the Fortran "val" variable equal to &I.

By the first two of these, there are 9 possible use cases – 3 possibilities for writing an attribute value, each of which has 3 possibilities for reading that value back. The following lists each of the 9 cases, and what happens in each.

Cases where C writes an attribute value:

In all of these cases, a pointer was written by C (e.g., a pointer to an int – but it could have been a pointer to anything, such as a struct). These scenarios each have 2 examples:

Example A: int foo = 3; MPI_Attr_put(..., &foo); Example B: struct foo bar; MPI_Attr_put(..., &bar);

  1. C reads the attribute value. Clearly, this is a "unity" case, and no translation occurs. A pointer is written, and that same pointer is returned.

Example A: int *ret; MPI_Attr_get(..., &ret); –> *ret will equal 3 Example B: struct foo *ret; MPI_Attr_get(..., &ret); –> *ret will point to the instance bar that was written

  1. Fortran MPI-1 reads the attribute value. The C pointer is cast to a fortran INTEGER (i.e., MPI_Fint) – potentially being truncated if sizeof(void*) > sizeof(INTEGER).

Example A: INTEGER ret CALL MPI_ATTR_GET(..., ret, ierr) –> ret will equal &foo, possibly truncaed Example B: INTEGER ret CALL MPI_ATTR_GET(..., ret, ierr) –> ret will equal &bar, possibly truncaed

  1. Fortran MPI-2 reads the attribute value. The C pointer is cast to a fortran INTEGER(KIND=MPI_ADDRESS_KIND) (i.e., a (MPI_Aint)).

Example A: INTEGER(KIND=MPI_ADDRESS_KIND) ret CALL MPI_COMM_GET_ATTR(..., ret, ierr) –> ret will equal &foo Example B: INTEGER(KIND=MPI_ADDRESS_KIND) ret CALL MPI_COMM_GET_ATTR(..., ret, ierr) –> ret will equal &bar

Cases where Fortran MPI-1 writes an attribute value:

In all of these cases, an INTEGER is written by Fortran.

Example: INTEGER FOO = 7 CALL MPI_ATTR_PUT(..., foo, ierr)

  1. C reads the attribute value. The value returned is a pointer that points to an INTEGER (i.e., an MPI_Fint) that has a value of 7. –> NOTE: The external MPI interface does not distinguish between this case and case 7. It is the programer's responsibility to code accordingly.

Example: MPI_Fint *ret; MPI_Attr_get(..., &ret); -> *ret will equal 7.

  1. Fortran MPI-1 reads the attribute value. This is the unity case; the same value is returned.

Example: INTEGER ret CALL MPI_ATTR_GET(..., ret, ierr) –> ret will equal 7

  1. Fortran MPI-2 reads the attribute value. The same value is returned, but potentially sign-extended if sizeof(INTEGER) < sizeof(INTEGER(KIND=MPI_ADDRESS_KIND)).

Example: INTEGER(KIND=MPI_ADDRESS_KIND) ret CALL MPI_COMM_GET_ATTR(..., ret, ierr) –> ret will equal 7

Cases where Fortran MPI-2 writes an attribute value:

In all of these cases, an INTEGER(KIND=MPI_ADDRESS_KIND) is written by Fortran.

Example A: INTEGER(KIND=MPI_ADDRESS_KIND) FOO = 12 CALL MPI_COMM_PUT_ATTR(..., foo, ierr) Example B: // Assume a platform where sizeof(void*) = 8 and // sizeof(INTEGER) = 4. INTEGER(KIND=MPI_ADDRESS_KIND) FOO = pow(2, 40) CALL MPI_COMM_PUT_ATTR(..., foo, ierr)

  1. C reads the attribute value. The value returned is a pointer that points to an INTEGER(KIND=MPI_ADDRESS_KIND) (i.e., a void*) that has a value of 12. –> NOTE: The external MPI interface does not distinguish between this case and case 4. It is the programer's responsibility to code accordingly.

Example A: MPI_Aint *ret; MPI_Attr_get(..., &ret); -> *ret will equal 12 Example B: MPI_Aint *ret; MPI_Attr_get(..., &ret); -> *ret will equal 2^40

  1. Fortran MPI-1 reads the attribute value. The same value is returned, but potentially truncated if sizeof(INTEGER) < sizeof(INTEGER(KIND=MPI_ADDRESS_KIND)).

Example A: INTEGER ret CALL MPI_ATTR_GET(..., ret, ierr) –> ret will equal 12 Example B: INTEGER ret CALL MPI_ATTR_GET(..., ret, ierr) –> ret will equal 0

  1. Fortran MPI-2 reads the attribute value. This is the unity case; the same value is returned.

Example A: INTEGER(KIND=MPI_ADDRESS_KIND) ret CALL MPI_COMM_GET_ATTR(..., ret, ierr) –> ret will equal 7 Example B: INTEGER(KIND=MPI_ADDRESS_KIND) ret CALL MPI_COMM_GET_ATTR(..., ret, ierr) –> ret will equal 2^40

Function Documentation

int ompi_attr_copy_all ( ompi_attribute_type_t  type,
void *  old_object,
void *  new_object,
opal_hash_table_t oldattr_hash,
opal_hash_table_t newkeyhash 
)

This to be used from functions like MPI_*_DUP inorder to copy all the attributes from the old Comm/Win/Dtype object to a new object.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
old_objectThe old COMM/WIN/DTYPE object (IN)
new_objectThe new COMM/WIN/DTYPE object (IN)
attr_hashThe attribute hash table hanging on old object(IN)
newattr_hashThe attribute hash table hanging on new object(IN)
Returns
OMPI error code

References ompi_attribute_keyval_t::attr_flag, COMM_ATTR, OBJ_RELEASE, opal_hash_table_get_first_key_uint32(), opal_hash_table_get_next_key_uint32(), opal_hash_table_get_value_uint32(), OPAL_THREAD_LOCK, OPAL_THREAD_UNLOCK, TYPE_ATTR, UNUSED_ATTR, and WIN_ATTR.

int ompi_attr_create_keyval ( ompi_attribute_type_t  type,
ompi_attribute_fn_ptr_union_t  copy_attr_fn,
ompi_attribute_fn_ptr_union_t  delete_attr_fn,
int *  key,
void *  extra_state,
int  flags,
void *  bindings_extra_state 
)

Create a new key for use by attribute of Comm/Win/Datatype.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
copy_attr_fnUnion variable containing the function pointer to be used in order to copy the attribute (IN)
delete_attr_fnFunction pointer to be used for deleting the attribute (IN)
keyThe newly created key is returned here (OUT)
extra_stateExtra state to hang off/do some special things (IN)
flagsFlags for the key – flags contain OMPI_KEYVAL_F77, OMPI_KEYVAL_PREDEFINED
bindings_extra_stateExtra state that, if non-NULL, will automatically be free()'ed by the C base when the keyval is destroyed.

NOTE: I have taken the assumption that user cannot modify/delete any predefined keys or the attributes attached. To accomplish this, all MPI* calls will have OMPI_KEYVAL_PREDEFINED set as 0. MPI implementors who will need to play with the predefined keys and attributes would call the ompi* functions here and not the MPI* functions, with OMPI_KEYVAL_PREDEFINED set to 1. END OF NOTE

NOTE: For the function pointers, you need to create a variable of the union type "ompi_attribute_fn_ptr_union_t" and assign the proper field. to be passed into this function END OF NOTE

Returns
OMPI return code
int ompi_attr_delete ( ompi_attribute_type_t  type,
void *  object,
opal_hash_table_t attr_hash,
int  key,
bool  predefined 
)

Delete an attribute on the comm/win/datatype.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
objectThe actual Comm/Win/Datatype object (IN)
attr_hashThe attribute hash table hanging on the object(IN)
keyKey val for the attribute (IN)
predefinedWhether the key is predefined or not 0/1 (IN)
Returns
OMPI error code

References ompi_attribute_keyval_t::attr_flag, ompi_attribute_keyval_t::attr_type, COMM_ATTR, OBJ_RELEASE, opal_hash_table_get_value_uint32(), opal_hash_table_remove_value_uint32(), OPAL_THREAD_LOCK, OPAL_THREAD_UNLOCK, TYPE_ATTR, and WIN_ATTR.

Referenced by ompi_attr_delete_all().

int ompi_attr_delete_all ( ompi_attribute_type_t  type,
void *  object,
opal_hash_table_t attr_hash 
)

This to be used to delete all the attributes from the Comm/Win/Dtype object in one shot.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
objectThe COMM/WIN/DTYPE object (IN)
attr_hashThe attribute hash table hanging on the object(IN)
Returns
OMPI error code

References ompi_attr_delete(), opal_hash_table_get_first_key_uint32(), opal_hash_table_get_next_key_uint32(), OPAL_THREAD_LOCK, and OPAL_THREAD_UNLOCK.

Referenced by ompi_mpi_finalize().

int ompi_attr_free_keyval ( ompi_attribute_type_t  type,
int *  key,
bool  predefined 
)

Free an attribute keyval.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
keykey, which is set to MPI_KEY_INVALID (IN/OUT)
Returns
OMPI error code

References ompi_attribute_keyval_t::attr_flag, ompi_attribute_keyval_t::attr_type, OBJ_RELEASE, opal_hash_table_get_value_uint32(), OPAL_THREAD_LOCK, and OPAL_THREAD_UNLOCK.

int ompi_attr_get_c ( opal_hash_table_t attr_hash,
int  key,
void **  attribute,
int *  flag 
)

Get an attribute on the comm/win/datatype in a form valid for C.

Parameters
attr_hashThe attribute hash table hanging on the object(IN)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (OUT)
flagFlag whether an attribute is associated with the key (OUT)
Returns
OMPI error code

All three of these functions (ompi_attr_get_c(), ompi_attr_get_fortran_mpi1(), and ompi_attr_get_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.

int ompi_attr_get_fortran_mpi1 ( opal_hash_table_t attr_hash,
int  key,
MPI_Fint *  attribute,
int *  flag 
)

Get an attribute on the comm/win/datatype in a form valid for Fortran MPI-1.

Parameters
attr_hashThe attribute hash table hanging on the object(IN)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (OUT)
flagFlag whether an attribute is associated with the key (OUT)
Returns
OMPI error code

All three of these functions (ompi_attr_get_c(), ompi_attr_get_fortran_mpi1(), and ompi_attr_get_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.

int ompi_attr_get_fortran_mpi2 ( opal_hash_table_t attr_hash,
int  key,
MPI_Aint *  attribute,
int *  flag 
)

Get an attribute on the comm/win/datatype in a form valid for Fortran MPI-2.

Parameters
attrhashThe attribute hash table hanging on the object(IN)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (OUT)
flagFlag whether an attribute is associated with the key (OUT)
Returns
OMPI error code

All three of these functions (ompi_attr_get_c(), ompi_attr_get_fortran_mpi1(), and ompi_attr_get_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.

int ompi_attr_init ( void  )

Initialize the main attribute hash that stores the keyvals and meta data.

Returns
OMPI return code

References OBJ_CONSTRUCT, opal_bitmap_init(), opal_bitmap_set_max_size(), and opal_hash_table_init().

Referenced by ompi_mpi_init().

int ompi_attr_set_c ( ompi_attribute_type_t  type,
void *  object,
opal_hash_table_t **  attr_hash,
int  key,
void *  attribute,
bool  predefined 
)

Set an attribute on the comm/win/datatype in a form valid for C.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
objectThe actual Comm/Win/Datatype object (IN)
attr_hashThe attribute hash table hanging on the object(IN/OUT)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (IN)
predefinedWhether the key is predefined or not 0/1 (IN)
Returns
OMPI error code

If (*attr_hash) == NULL, a new hash will be created and initialized.

All three of these functions (ompi_attr_set_c(), ompi_attr_set_fortran_mpi1(), and ompi_attr_set_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.

int ompi_attr_set_fortran_mpi1 ( ompi_attribute_type_t  type,
void *  object,
opal_hash_table_t **  attr_hash,
int  key,
MPI_Fint  attribute,
bool  predefined 
)

Set an attribute on the comm/win/datatype in a form valid for Fortran MPI-1.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
objectThe actual Comm/Win/Datatype object (IN)
attr_hashThe attribute hash table hanging on the object(IN/OUT)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (IN)
predefinedWhether the key is predefined or not 0/1 (IN)
Returns
OMPI error code

If (*attr_hash) == NULL, a new hash will be created and initialized.

All three of these functions (ompi_attr_set_c(), ompi_attr_set_fortran_mpi1(), and ompi_attr_set_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.

int ompi_attr_set_fortran_mpi2 ( ompi_attribute_type_t  type,
void *  object,
opal_hash_table_t **  attr_hash,
int  key,
MPI_Aint  attribute,
bool  predefined 
)

Set an attribute on the comm/win/datatype in a form valid for Fortran MPI-2.

Parameters
typeType of attribute (COMM/WIN/DTYPE) (IN)
objectThe actual Comm/Win/Datatype object (IN)
attr_hashThe attribute hash table hanging on the object(IN/OUT)
keyKey val for the attribute (IN)
attributeThe actual attribute pointer (IN)
predefinedWhether the key is predefined or not 0/1 (IN)
Returns
OMPI error code

If (*attr_hash) == NULL, a new hash will be created and initialized.

All three of these functions (ompi_attr_set_c(), ompi_attr_set_fortran_mpi1(), and ompi_attr_set_fortran_mpi2()) could have been combined into one function that took some kind of (void*) and an enum to indicate which way to translate the final representation, but that just seemed to make an already complicated situation more complicated through yet another layer of indirection.

So yes, this is more code, but it's clearer and less error-prone (read: better) this way.