2014-05-15 15:59:51 +00:00
|
|
|
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
2005-08-12 02:41:14 +00:00
|
|
|
/*
|
2007-02-21 16:18:43 +00:00
|
|
|
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
2005-11-05 19:57:48 +00:00
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2014-05-20 08:46:57 +00:00
|
|
|
* Copyright (c) 2004-2014 The University of Tennessee and The University
|
2005-11-05 19:57:48 +00:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
2015-06-23 20:59:57 -07:00
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
2005-08-12 02:41:14 +00:00
|
|
|
* University of Stuttgart. All rights reserved.
|
2006-03-27 22:48:12 +00:00
|
|
|
* Copyright (c) 2004-2006 The Regents of the University of California.
|
2005-08-12 02:41:14 +00:00
|
|
|
* All rights reserved.
|
2015-08-31 14:57:55 -06:00
|
|
|
* Copyright (c) 2007-2015 Los Alamos National Security, LLC. All rights
|
2015-06-23 20:59:57 -07:00
|
|
|
* reserved.
|
2015-06-25 15:53:29 -07:00
|
|
|
* Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved.
|
As per the email discussion, revise the sparse handling of hostnames so that we avoid potential infinite loops while allowing large-scale users to improve their startup time:
* add a new MCA param orte_hostname_cutoff to specify the number of nodes at which we stop including hostnames. This defaults to INT_MAX => always include hostnames. If a value is given, then we will include hostnames for any allocation smaller than the given limit.
* remove ompi_proc_get_hostname. Replace all occurrences with a direct link to ompi_proc_t's proc_hostname, protected by appropriate "if NULL"
* modify the OMPI-ORTE integration component so that any call to modex_recv automatically loads the ompi_proc_t->proc_hostname field as well as returning the requested info. Thus, any process whose modex info you retrieve will automatically receive the hostname. Note that on-demand retrieval is still enabled - i.e., if we are running under direct launch with PMI, the hostname will be fetched upon first call to modex_recv, and then the ompi_proc_t->proc_hostname field will be loaded
* removed a stale MCA param "mpi_keep_peer_hostnames" that was no longer used anywhere in the code base
* added an envar lookup in ess/pmi for the number of nodes in the allocation. Sadly, PMI itself doesn't provide that info, so we have to get it a different way. Currently, we support PBS-based systems and SLURM - for any other, rank0 will emit a warning and we assume max number of daemons so we will always retain hostnames
This commit was SVN r29052.
2013-08-20 18:59:36 +00:00
|
|
|
* Copyright (c) 2013 Intel, Inc. All rights reserved
|
2014-03-14 20:17:47 +00:00
|
|
|
* Copyright (c) 2014 NVIDIA Corporation. All rights reserved.
|
2014-05-16 04:43:18 +00:00
|
|
|
* Copyright (c) 2014 Research Organization for Information Science
|
|
|
|
* and Technology (RIST). All rights reserved.
|
2014-11-14 13:16:45 -07:00
|
|
|
* Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights
|
|
|
|
* reserved.
|
2005-08-12 02:41:14 +00:00
|
|
|
* $COPYRIGHT$
|
2015-06-23 20:59:57 -07:00
|
|
|
*
|
2005-08-12 02:41:14 +00:00
|
|
|
* Additional copyrights may follow
|
2015-06-23 20:59:57 -07:00
|
|
|
*
|
2005-08-12 02:41:14 +00:00
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ompi_config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2009-03-03 22:25:13 +00:00
|
|
|
#include "opal/class/opal_bitmap.h"
|
2008-09-11 20:52:58 +00:00
|
|
|
#include "opal/util/argv.h"
|
2013-02-12 21:10:11 +00:00
|
|
|
#include "opal/util/show_help.h"
|
2009-02-14 02:26:12 +00:00
|
|
|
#include "opal/util/output.h"
|
2005-09-12 20:22:59 +00:00
|
|
|
#include "ompi/mca/bml/bml.h"
|
2007-02-21 16:18:43 +00:00
|
|
|
#include "ompi/mca/bml/base/base.h"
|
George did the work and deserves all the credit for it. Ralph did the merge, and deserves whatever blame results from errors in it :-)
WHAT: Open our low-level communication infrastructure by moving all necessary components (btl/rcache/allocator/mpool) down in OPAL
All the components required for inter-process communications are currently deeply integrated in the OMPI layer. Several groups/institutions have express interest in having a more generic communication infrastructure, without all the OMPI layer dependencies. This communication layer should be made available at a different software level, available to all layers in the Open MPI software stack. As an example, our ORTE layer could replace the current OOB and instead use the BTL directly, gaining access to more reactive network interfaces than TCP. Similarly, external software libraries could take advantage of our highly optimized AM (active message) communication layer for their own purpose. UTK with support from Sandia, developped a version of Open MPI where the entire communication infrastucture has been moved down to OPAL (btl/rcache/allocator/mpool). Most of the moved components have been updated to match the new schema, with few exceptions (mainly BTLs where I have no way of compiling/testing them). Thus, the completion of this RFC is tied to being able to completing this move for all BTLs. For this we need help from the rest of the Open MPI community, especially those supporting some of the BTLs. A non-exhaustive list of BTLs that qualify here is: mx, portals4, scif, udapl, ugni, usnic.
This commit was SVN r32317.
2014-07-26 00:47:28 +00:00
|
|
|
#include "opal/mca/btl/btl.h"
|
|
|
|
#include "opal/mca/btl/base/base.h"
|
2015-06-23 20:59:57 -07:00
|
|
|
#include "ompi/mca/bml/base/bml_base_btl.h"
|
2005-08-12 02:41:14 +00:00
|
|
|
#include "bml_r2.h"
|
2005-09-12 20:22:59 +00:00
|
|
|
#include "ompi/proc/proc.h"
|
2005-08-12 02:41:14 +00:00
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
extern mca_bml_base_component_t mca_bml_r2_component;
|
2005-08-12 02:41:14 +00:00
|
|
|
|
2008-09-11 20:52:58 +00:00
|
|
|
/* Names of all the BTL components that this BML is aware of */
|
|
|
|
static char *btl_names = NULL;
|
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
static int btl_exclusivity_compare(const void* arg1, const void* arg2)
|
|
|
|
{
|
|
|
|
mca_btl_base_module_t* btl1 = *(struct mca_btl_base_module_t**)arg1;
|
|
|
|
mca_btl_base_module_t* btl2 = *(struct mca_btl_base_module_t**)arg2;
|
|
|
|
if( btl1->btl_exclusivity > btl2->btl_exclusivity ) {
|
|
|
|
return -1;
|
|
|
|
} else if (btl1->btl_exclusivity == btl2->btl_exclusivity ) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mca_bml_r2_add_btls( void )
|
|
|
|
{
|
2008-09-11 20:52:58 +00:00
|
|
|
int i;
|
2015-06-23 20:59:57 -07:00
|
|
|
opal_list_t *btls = NULL;
|
2005-08-12 02:41:14 +00:00
|
|
|
mca_btl_base_selected_module_t* selected_btl;
|
2015-06-23 20:59:57 -07:00
|
|
|
size_t num_btls = 0;
|
2008-09-11 20:52:58 +00:00
|
|
|
char **btl_names_argv = NULL;
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2005-08-24 10:39:23 +00:00
|
|
|
if(true == mca_bml_r2.btls_added) {
|
2015-06-23 20:59:57 -07:00
|
|
|
return OMPI_SUCCESS;
|
2005-08-24 10:39:23 +00:00
|
|
|
}
|
2005-08-15 19:39:56 +00:00
|
|
|
|
|
|
|
/* build an array of r2s and r2 modules */
|
|
|
|
btls = &mca_btl_base_modules_initialized;
|
|
|
|
num_btls = opal_list_get_size(btls);
|
2005-08-12 02:41:14 +00:00
|
|
|
|
|
|
|
mca_bml_r2.num_btl_modules = 0;
|
|
|
|
mca_bml_r2.num_btl_progress = 0;
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
mca_bml_r2.btl_modules = (mca_btl_base_module_t **)malloc(sizeof(mca_btl_base_module_t*) * num_btls);
|
|
|
|
mca_bml_r2.btl_progress = (mca_btl_base_component_progress_fn_t*)malloc(sizeof(mca_btl_base_component_progress_fn_t) * num_btls);
|
2015-06-23 20:59:57 -07:00
|
|
|
|
|
|
|
if (NULL == mca_bml_r2.btl_modules ||
|
2005-08-12 02:41:14 +00:00
|
|
|
NULL == mca_bml_r2.btl_progress) {
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
|
|
|
|
2014-11-14 13:16:45 -07:00
|
|
|
OPAL_LIST_FOREACH(selected_btl, btls, mca_btl_base_selected_module_t) {
|
2005-08-12 02:41:14 +00:00
|
|
|
mca_btl_base_module_t *btl = selected_btl->btl_module;
|
|
|
|
mca_bml_r2.btl_modules[mca_bml_r2.num_btl_modules++] = btl;
|
2008-09-11 20:52:58 +00:00
|
|
|
for (i = 0; NULL != btl_names_argv && NULL != btl_names_argv[i]; ++i) {
|
2015-06-23 20:59:57 -07:00
|
|
|
if (0 ==
|
2008-09-11 20:52:58 +00:00
|
|
|
strcmp(btl_names_argv[i],
|
|
|
|
btl->btl_component->btl_version.mca_component_name)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL == btl_names_argv || NULL == btl_names_argv[i]) {
|
2015-06-23 20:59:57 -07:00
|
|
|
opal_argv_append_nosize(&btl_names_argv,
|
2008-09-11 20:52:58 +00:00
|
|
|
btl->btl_component->btl_version.mca_component_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL != btl_names_argv) {
|
|
|
|
btl_names = opal_argv_join(btl_names_argv, ' ');
|
|
|
|
opal_argv_free(btl_names_argv);
|
|
|
|
} else {
|
|
|
|
btl_names = strdup("no devices available");
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* sort r2 list by exclusivity */
|
2015-06-23 20:59:57 -07:00
|
|
|
qsort(mca_bml_r2.btl_modules,
|
|
|
|
mca_bml_r2.num_btl_modules,
|
|
|
|
sizeof(struct mca_btl_base_module_t*),
|
2005-08-12 02:41:14 +00:00
|
|
|
btl_exclusivity_compare);
|
2015-06-23 20:59:57 -07:00
|
|
|
mca_bml_r2.btls_added = true;
|
2005-08-12 02:41:14 +00:00
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-07-01 11:34:23 +00:00
|
|
|
static int btl_bandwidth_compare(const void *v1, const void *v2)
|
|
|
|
{
|
|
|
|
mca_bml_base_btl_t *b1 = (mca_bml_base_btl_t*)v1,
|
|
|
|
*b2 = (mca_bml_base_btl_t*)v2;
|
|
|
|
|
|
|
|
return b2->btl->btl_bandwidth - b1->btl->btl_bandwidth;
|
|
|
|
}
|
|
|
|
|
2014-11-14 13:16:45 -07:00
|
|
|
static void mca_bml_r2_calculate_bandwidth_latency (mca_bml_base_btl_array_t *btl_array, double *total_bandwidth, uint32_t *latency)
|
|
|
|
{
|
|
|
|
const size_t array_length = mca_bml_base_btl_array_get_size (btl_array);
|
|
|
|
|
|
|
|
*latency = UINT_MAX;
|
|
|
|
*total_bandwidth = 0.;
|
|
|
|
|
|
|
|
for (size_t i = 0 ; i < array_length ; ++i) {
|
|
|
|
mca_bml_base_btl_t *bml_btl = mca_bml_base_btl_array_get_index (btl_array, i);
|
|
|
|
mca_btl_base_module_t *btl = bml_btl->btl;
|
|
|
|
*total_bandwidth += btl->btl_bandwidth;
|
|
|
|
if (btl->btl_latency < *latency) {
|
|
|
|
*latency = btl->btl_latency;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
static mca_bml_base_endpoint_t *mca_bml_r2_allocate_endpoint (ompi_proc_t *proc) {
|
|
|
|
mca_bml_base_endpoint_t *bml_endpoint;
|
|
|
|
|
|
|
|
/* allocate bml specific proc data */
|
|
|
|
bml_endpoint = OBJ_NEW(mca_bml_base_endpoint_t);
|
|
|
|
if (NULL == bml_endpoint) {
|
|
|
|
opal_output(0, "mca_bml_r2_add_procs: unable to allocate resources");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* preallocate space in array for max number of r2s */
|
|
|
|
mca_bml_base_btl_array_reserve(&bml_endpoint->btl_eager, mca_bml_r2.num_btl_modules);
|
|
|
|
mca_bml_base_btl_array_reserve(&bml_endpoint->btl_send, mca_bml_r2.num_btl_modules);
|
|
|
|
mca_bml_base_btl_array_reserve(&bml_endpoint->btl_rdma, mca_bml_r2.num_btl_modules);
|
|
|
|
bml_endpoint->btl_max_send_size = -1;
|
|
|
|
bml_endpoint->btl_proc = proc;
|
|
|
|
proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML] = bml_endpoint;
|
|
|
|
|
|
|
|
bml_endpoint->btl_flags_or = 0;
|
|
|
|
return bml_endpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mca_bml_r2_register_progress (mca_btl_base_module_t *btl)
|
|
|
|
{
|
|
|
|
if (NULL != btl->btl_component->btl_progress) {
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for (size_t p = 0 ; p < mca_bml_r2.num_btl_progress ; ++p) {
|
|
|
|
if(mca_bml_r2.btl_progress[p] == btl->btl_component->btl_progress) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == false) {
|
|
|
|
mca_bml_r2.btl_progress[mca_bml_r2.num_btl_progress++] =
|
|
|
|
btl->btl_component->btl_progress;
|
|
|
|
opal_progress_register (btl->btl_component->btl_progress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mca_bml_r2_endpoint_add_btl (struct ompi_proc_t *proc, mca_bml_base_endpoint_t *bml_endpoint,
|
|
|
|
mca_btl_base_module_t *btl, struct mca_btl_base_endpoint_t *btl_endpoint)
|
|
|
|
{
|
|
|
|
mca_bml_base_btl_t* bml_btl = NULL;
|
|
|
|
int btl_flags = btl->btl_flags;
|
|
|
|
bool btl_in_use = false;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* NTH: these flags should have been sanitized by the btl. Once that is verified these
|
|
|
|
* checks can be safely removed. */
|
|
|
|
if ((btl_flags & MCA_BTL_FLAGS_PUT) && (NULL == btl->btl_put)) {
|
|
|
|
opal_output(0, "mca_bml_r2_add_procs: The PUT flag is specified for"
|
|
|
|
" the %s BTL without any PUT function attached. Discard the flag !",
|
|
|
|
btl->btl_component->btl_version.mca_component_name);
|
|
|
|
btl_flags ^= MCA_BTL_FLAGS_PUT;
|
|
|
|
}
|
|
|
|
if ((btl_flags & MCA_BTL_FLAGS_GET) && (NULL == btl->btl_get)) {
|
|
|
|
opal_output(0, "mca_bml_r2_add_procs: The GET flag is specified for"
|
|
|
|
" the %s BTL without any GET function attached. Discard the flag !",
|
|
|
|
btl->btl_component->btl_version.mca_component_name);
|
|
|
|
btl_flags ^= MCA_BTL_FLAGS_GET;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((btl_flags & (MCA_BTL_FLAGS_PUT | MCA_BTL_FLAGS_GET | MCA_BTL_FLAGS_SEND)) == 0) {
|
|
|
|
/* If no protocol specified, we have 2 choices: we ignore the BTL
|
|
|
|
* as we don't know which protocl to use, or we suppose that all
|
|
|
|
* BTLs support the send protocol. This is really a btl error as
|
|
|
|
* these flags should have been sanitized by the btl. */
|
|
|
|
btl_flags |= MCA_BTL_FLAGS_SEND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (btl_flags & MCA_BTL_FLAGS_SEND) {
|
|
|
|
/* dont allow an additional BTL with a lower exclusivity ranking */
|
|
|
|
size = mca_bml_base_btl_array_get_size (&bml_endpoint->btl_send);
|
2015-09-10 16:33:38 -06:00
|
|
|
bml_btl = mca_bml_base_btl_array_get_index (&bml_endpoint->btl_send, size - 1);
|
2015-08-31 14:57:55 -06:00
|
|
|
|
2015-11-06 13:26:32 -08:00
|
|
|
if (!bml_btl || bml_btl->btl->btl_exclusivity <= btl->btl_exclusivity) {
|
2015-08-31 14:57:55 -06:00
|
|
|
/* this btl has higher exclusivity than an existing btl or none exists */
|
|
|
|
|
|
|
|
opal_output_verbose(1, opal_btl_base_framework.framework_output,
|
|
|
|
"mca: bml: Using %s btl for send to %s on node %s",
|
|
|
|
btl->btl_component->btl_version.mca_component_name,
|
|
|
|
OMPI_NAME_PRINT(&proc->super.proc_name),
|
|
|
|
proc->super.proc_hostname);
|
|
|
|
|
|
|
|
/* cache the endpoint on the proc */
|
|
|
|
if (NULL == bml_btl || (bml_btl->btl->btl_exclusivity <= btl->btl_exclusivity)) {
|
|
|
|
bml_btl = mca_bml_base_btl_array_insert (&bml_endpoint->btl_send);
|
|
|
|
bml_btl->btl = btl;
|
|
|
|
bml_btl->btl_endpoint = btl_endpoint;
|
|
|
|
bml_btl->btl_weight = 0;
|
|
|
|
bml_btl->btl_flags = btl_flags;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* calculate the bitwise OR of the btl flags
|
|
|
|
*/
|
|
|
|
bml_endpoint->btl_flags_or |= bml_btl->btl_flags;
|
|
|
|
} else {
|
|
|
|
opal_output_verbose(20, opal_btl_base_framework.framework_output,
|
|
|
|
"mca: bml: Not using %s btl for send to %s on node %s "
|
|
|
|
"because %s btl has higher exclusivity (%d > %d)",
|
|
|
|
btl->btl_component->btl_version.mca_component_name,
|
|
|
|
OMPI_NAME_PRINT(&proc->super.proc_name), proc->super.proc_hostname,
|
|
|
|
bml_btl->btl->btl_component->btl_version.mca_component_name,
|
|
|
|
bml_btl->btl->btl_exclusivity,
|
|
|
|
btl->btl_exclusivity);
|
|
|
|
}
|
|
|
|
|
|
|
|
btl_in_use = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* always add rdma endpoints */
|
|
|
|
if ((btl_flags & MCA_BTL_FLAGS_RDMA) &&
|
|
|
|
!((proc->super.proc_arch != ompi_proc_local_proc->super.proc_arch) &&
|
|
|
|
(0 == (btl->btl_flags & MCA_BTL_FLAGS_HETEROGENEOUS_RDMA)))) {
|
|
|
|
mca_bml_base_btl_t *bml_btl_rdma = mca_bml_base_btl_array_insert(&bml_endpoint->btl_rdma);
|
|
|
|
|
|
|
|
bml_btl_rdma->btl = btl;
|
|
|
|
bml_btl_rdma->btl_endpoint = btl_endpoint;
|
|
|
|
bml_btl_rdma->btl_weight = 0;
|
|
|
|
bml_btl_rdma->btl_flags = btl_flags;
|
|
|
|
|
|
|
|
if (bml_endpoint->btl_pipeline_send_length < btl->btl_rdma_pipeline_send_length) {
|
|
|
|
bml_endpoint->btl_pipeline_send_length = btl->btl_rdma_pipeline_send_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bml_endpoint->btl_send_limit < btl->btl_min_rdma_pipeline_size) {
|
|
|
|
bml_endpoint->btl_send_limit = btl->btl_min_rdma_pipeline_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
btl_in_use = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return btl_in_use ? OMPI_SUCCESS : OMPI_ERR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mca_bml_r2_compute_endpoint_metrics (mca_bml_base_endpoint_t *bml_endpoint)
|
|
|
|
{
|
|
|
|
double total_bandwidth = 0;
|
|
|
|
uint32_t latency;
|
|
|
|
size_t n_send, n_rdma;
|
|
|
|
|
|
|
|
/* (1) determine the total bandwidth available across all btls
|
|
|
|
* note that we need to do this here, as we may already have btls configured
|
|
|
|
* (2) determine the highest priority ranking for latency
|
|
|
|
* (3) compute the maximum amount of bytes that can be send without any
|
|
|
|
* weighting. Once the left over is smaller than this number we will
|
|
|
|
* start using the weight to compute the correct amount.
|
|
|
|
*/
|
|
|
|
n_send = mca_bml_base_btl_array_get_size (&bml_endpoint->btl_send);
|
|
|
|
n_rdma = mca_bml_base_btl_array_get_size (&bml_endpoint->btl_rdma);
|
|
|
|
|
|
|
|
/* sort BTLs in descending order according to bandwidth value */
|
|
|
|
qsort (bml_endpoint->btl_send.bml_btls, n_send,
|
|
|
|
sizeof(mca_bml_base_btl_t), btl_bandwidth_compare);
|
|
|
|
|
|
|
|
bml_endpoint->btl_rdma_index = 0;
|
|
|
|
|
|
|
|
mca_bml_r2_calculate_bandwidth_latency (&bml_endpoint->btl_send, &total_bandwidth, &latency);
|
|
|
|
|
|
|
|
/* (1) set the weight of each btl as a percentage of overall bandwidth
|
|
|
|
* (2) copy all btl instances at the highest priority ranking into the
|
|
|
|
* list of btls used for first fragments
|
|
|
|
*/
|
|
|
|
for (size_t n_index = 0 ; n_index < n_send ; ++n_index) {
|
|
|
|
mca_bml_base_btl_t *bml_btl =
|
|
|
|
mca_bml_base_btl_array_get_index(&bml_endpoint->btl_send, n_index);
|
|
|
|
mca_btl_base_module_t *btl = bml_btl->btl;
|
|
|
|
|
|
|
|
/* compute weighting factor for this r2 */
|
|
|
|
if(btl->btl_bandwidth > 0) {
|
|
|
|
bml_btl->btl_weight = (float)(btl->btl_bandwidth / total_bandwidth);
|
|
|
|
} else {
|
|
|
|
bml_btl->btl_weight = (float)(1.0 / n_send);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check to see if this r2 is already in the array of r2s
|
|
|
|
* used for first fragments - if not add it.
|
|
|
|
*/
|
|
|
|
if(btl->btl_latency == latency) {
|
|
|
|
mca_bml_base_btl_t* bml_btl_new =
|
|
|
|
mca_bml_base_btl_array_insert(&bml_endpoint->btl_eager);
|
|
|
|
*bml_btl_new = *bml_btl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set endpoint max send size as min of available btls */
|
|
|
|
if (bml_endpoint->btl_max_send_size > btl->btl_max_send_size)
|
|
|
|
bml_endpoint->btl_max_send_size = btl->btl_max_send_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sort BTLs in descending order according to bandwidth value */
|
|
|
|
qsort(bml_endpoint->btl_rdma.bml_btls, n_rdma,
|
|
|
|
sizeof(mca_bml_base_btl_t), btl_bandwidth_compare);
|
|
|
|
|
|
|
|
mca_bml_r2_calculate_bandwidth_latency (&bml_endpoint->btl_rdma, &total_bandwidth, &latency);
|
|
|
|
|
|
|
|
/* set rdma btl weights */
|
|
|
|
for (size_t n_index = 0 ; n_index < n_rdma ; ++n_index) {
|
|
|
|
mca_bml_base_btl_t *bml_btl =
|
|
|
|
mca_bml_base_btl_array_get_index(&bml_endpoint->btl_rdma, n_index);
|
|
|
|
|
|
|
|
/* compute weighting factor for this r2 */
|
|
|
|
if (bml_btl->btl->btl_bandwidth > 0.0) {
|
|
|
|
bml_btl->btl_weight = (float)(bml_btl->btl->btl_bandwidth / total_bandwidth);
|
|
|
|
} else {
|
|
|
|
bml_btl->btl_weight = (float)(1.0 / n_rdma);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mca_bml_r2_add_proc (struct ompi_proc_t *proc)
|
|
|
|
{
|
|
|
|
mca_bml_base_endpoint_t *bml_endpoint;
|
|
|
|
/* at least one btl is in use */
|
2015-09-11 09:39:10 -06:00
|
|
|
bool btl_in_use = false;
|
2015-08-31 14:57:55 -06:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (OPAL_UNLIKELY(NULL == proc)) {
|
|
|
|
return OMPI_ERR_BAD_PARAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if this endpoint is already set up */
|
|
|
|
if (NULL != proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML]) {
|
|
|
|
OBJ_RETAIN(proc);
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add btls if not already done */
|
|
|
|
if (OMPI_SUCCESS != (rc = mca_bml_r2_add_btls())) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bml_endpoint = mca_bml_r2_allocate_endpoint (proc);
|
|
|
|
if (OPAL_UNLIKELY(NULL == bml_endpoint)) {
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:33:38 -06:00
|
|
|
for (size_t p_index = 0 ; p_index < mca_bml_r2.num_btl_modules ; ++p_index) {
|
2015-08-31 14:57:55 -06:00
|
|
|
mca_btl_base_module_t *btl = mca_bml_r2.btl_modules[p_index];
|
|
|
|
struct mca_btl_base_endpoint_t *btl_endpoint = NULL;
|
|
|
|
|
|
|
|
/* if the r2 can reach the destination proc it sets the
|
|
|
|
* corresponding bit (proc index) in the reachable bitmap
|
|
|
|
* and can return addressing information for each proc
|
|
|
|
* that is passed back to the r2 on data transfer calls
|
|
|
|
*/
|
|
|
|
rc = btl->btl_add_procs (btl, 1, (opal_proc_t **) &proc, &btl_endpoint, NULL);
|
|
|
|
if (OMPI_SUCCESS != rc || NULL == btl_endpoint) {
|
|
|
|
/* This BTL has troubles adding the nodes. Let's continue maybe some other BTL
|
|
|
|
* can take care of this task. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = mca_bml_r2_endpoint_add_btl (proc, bml_endpoint, btl, btl_endpoint);
|
|
|
|
if (OMPI_SUCCESS != rc) {
|
|
|
|
btl->btl_del_procs (btl, 1, (opal_proc_t **) &proc, &btl_endpoint);
|
|
|
|
} else {
|
|
|
|
mca_bml_r2_register_progress (btl);
|
|
|
|
btl_in_use = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!btl_in_use) {
|
|
|
|
/* no btl is available for this proc */
|
|
|
|
if (mca_bml_r2.show_unreach_errors) {
|
|
|
|
opal_show_help ("help-mca-bml-r2.txt", "unreachable proc", true,
|
|
|
|
OMPI_NAME_PRINT(&(ompi_proc_local_proc->super.proc_name)),
|
|
|
|
(NULL != ompi_proc_local_proc->super.proc_hostname ?
|
|
|
|
ompi_proc_local_proc->super.proc_hostname : "unknown!"),
|
|
|
|
OMPI_NAME_PRINT(&(proc->super.proc_name)),
|
|
|
|
(NULL != proc->super.proc_hostname ?
|
|
|
|
proc->super.proc_hostname : "unknown!"),
|
|
|
|
btl_names);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OMPI_ERR_UNREACH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compute metrics for registered btls */
|
|
|
|
mca_bml_r2_compute_endpoint_metrics (bml_endpoint);
|
|
|
|
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
/*
|
2007-07-25 17:26:23 +00:00
|
|
|
* For each proc setup a datastructure that indicates the BTLs
|
2005-08-12 02:41:14 +00:00
|
|
|
* that can be used to reach the destination.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
static int mca_bml_r2_add_procs( size_t nprocs,
|
|
|
|
struct ompi_proc_t** procs,
|
2009-03-03 22:25:13 +00:00
|
|
|
struct opal_bitmap_t* reachable )
|
2005-08-12 02:41:14 +00:00
|
|
|
{
|
2015-08-31 14:57:55 -06:00
|
|
|
size_t n_new_procs = 0;
|
2015-06-23 20:59:57 -07:00
|
|
|
struct mca_btl_base_endpoint_t ** btl_endpoints = NULL;
|
|
|
|
struct ompi_proc_t** new_procs = NULL;
|
2008-07-24 10:33:17 +00:00
|
|
|
int rc, ret = OMPI_SUCCESS;
|
2005-08-15 19:39:56 +00:00
|
|
|
|
2005-08-24 10:39:23 +00:00
|
|
|
if(0 == nprocs) {
|
2005-08-12 02:41:14 +00:00
|
|
|
return OMPI_SUCCESS;
|
2005-08-24 10:39:23 +00:00
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2005-08-24 10:39:23 +00:00
|
|
|
if(OMPI_SUCCESS != (rc = mca_bml_r2_add_btls()) ) {
|
2005-08-12 02:41:14 +00:00
|
|
|
return rc;
|
2005-08-24 10:39:23 +00:00
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
/* Select only the procs that don't yet have the BML proc struct. This prevent
|
2014-01-26 17:26:04 +00:00
|
|
|
* us from calling btl->add_procs several times on the same destination proc.
|
2008-09-30 15:47:43 +00:00
|
|
|
*/
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t p_index = 0 ; p_index < nprocs ; ++p_index) {
|
2015-06-23 20:59:57 -07:00
|
|
|
struct ompi_proc_t* proc = procs[p_index];
|
2008-09-30 15:47:43 +00:00
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
if(NULL != proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML]) {
|
2008-09-30 15:47:43 +00:00
|
|
|
continue; /* go to the next proc */
|
2005-08-12 16:59:15 +00:00
|
|
|
}
|
2008-09-30 15:47:43 +00:00
|
|
|
/* Allocate the new_procs on demand */
|
|
|
|
if( NULL == new_procs ) {
|
|
|
|
new_procs = (struct ompi_proc_t **)malloc(nprocs * sizeof(struct ompi_proc_t *));
|
|
|
|
if( NULL == new_procs ) {
|
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
|
|
|
}
|
2014-01-26 17:26:04 +00:00
|
|
|
OBJ_RETAIN(proc);
|
2015-06-23 20:59:57 -07:00
|
|
|
new_procs[n_new_procs++] = proc;
|
2005-08-12 16:59:15 +00:00
|
|
|
}
|
2005-10-12 20:59:25 +00:00
|
|
|
|
|
|
|
if ( 0 == n_new_procs ) {
|
2007-04-14 02:06:05 +00:00
|
|
|
return OMPI_SUCCESS;
|
2005-10-12 20:59:25 +00:00
|
|
|
}
|
2008-09-30 15:47:43 +00:00
|
|
|
|
|
|
|
/* Starting from here we only work on the unregistered procs */
|
2015-06-23 20:59:57 -07:00
|
|
|
procs = new_procs;
|
|
|
|
nprocs = n_new_procs;
|
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
/* attempt to add all procs to each r2 */
|
2015-06-23 20:59:57 -07:00
|
|
|
btl_endpoints = (struct mca_btl_base_endpoint_t **)
|
|
|
|
malloc(nprocs * sizeof(struct mca_btl_base_endpoint_t*));
|
2005-08-24 10:39:23 +00:00
|
|
|
if (NULL == btl_endpoints) {
|
2008-09-30 15:47:43 +00:00
|
|
|
free(new_procs);
|
2005-08-24 10:39:23 +00:00
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
2008-09-11 20:52:58 +00:00
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t p_index = 0 ; p_index < mca_bml_r2.num_btl_modules ; ++p_index) {
|
|
|
|
mca_btl_base_module_t *btl = mca_bml_r2.btl_modules[p_index];
|
2005-08-12 02:41:14 +00:00
|
|
|
int btl_inuse = 0;
|
2008-09-11 20:52:58 +00:00
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
/* if the r2 can reach the destination proc it sets the
|
|
|
|
* corresponding bit (proc index) in the reachable bitmap
|
|
|
|
* and can return addressing information for each proc
|
|
|
|
* that is passed back to the r2 on data transfer calls
|
|
|
|
*/
|
2009-03-03 22:25:13 +00:00
|
|
|
opal_bitmap_clear_all_bits(reachable);
|
2015-06-23 20:59:57 -07:00
|
|
|
memset(btl_endpoints, 0, nprocs *sizeof(struct mca_btl_base_endpoint_t*));
|
2005-08-12 02:41:14 +00:00
|
|
|
|
George did the work and deserves all the credit for it. Ralph did the merge, and deserves whatever blame results from errors in it :-)
WHAT: Open our low-level communication infrastructure by moving all necessary components (btl/rcache/allocator/mpool) down in OPAL
All the components required for inter-process communications are currently deeply integrated in the OMPI layer. Several groups/institutions have express interest in having a more generic communication infrastructure, without all the OMPI layer dependencies. This communication layer should be made available at a different software level, available to all layers in the Open MPI software stack. As an example, our ORTE layer could replace the current OOB and instead use the BTL directly, gaining access to more reactive network interfaces than TCP. Similarly, external software libraries could take advantage of our highly optimized AM (active message) communication layer for their own purpose. UTK with support from Sandia, developped a version of Open MPI where the entire communication infrastucture has been moved down to OPAL (btl/rcache/allocator/mpool). Most of the moved components have been updated to match the new schema, with few exceptions (mainly BTLs where I have no way of compiling/testing them). Thus, the completion of this RFC is tied to being able to completing this move for all BTLs. For this we need help from the rest of the Open MPI community, especially those supporting some of the BTLs. A non-exhaustive list of BTLs that qualify here is: mx, portals4, scif, udapl, ugni, usnic.
This commit was SVN r32317.
2014-07-26 00:47:28 +00:00
|
|
|
rc = btl->btl_add_procs(btl, n_new_procs, (opal_proc_t**)new_procs, btl_endpoints, reachable);
|
2015-08-31 14:57:55 -06:00
|
|
|
if (OMPI_SUCCESS != rc) {
|
|
|
|
/* This BTL encountered an error while adding procs. Continue in case some other
|
|
|
|
* BTL(s) can be used. */
|
2008-07-29 18:38:11 +00:00
|
|
|
continue;
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
/* for each proc that is reachable */
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t p = 0 ; p < n_new_procs ; ++p) {
|
|
|
|
if (!opal_bitmap_is_set_bit(reachable, p)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-11-14 13:16:45 -07:00
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
ompi_proc_t *proc = new_procs[p];
|
|
|
|
mca_bml_base_endpoint_t *bml_endpoint =
|
|
|
|
(mca_bml_base_endpoint_t *) proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML];
|
|
|
|
|
|
|
|
if (NULL == bml_endpoint) {
|
|
|
|
bml_endpoint = mca_bml_r2_allocate_endpoint (proc);
|
|
|
|
if (NULL == bml_endpoint) {
|
|
|
|
free(btl_endpoints);
|
|
|
|
free(new_procs);
|
|
|
|
return OPAL_ERR_OUT_OF_RESOURCE;
|
2014-11-14 13:16:45 -07:00
|
|
|
}
|
2015-08-31 14:57:55 -06:00
|
|
|
}
|
2014-11-14 13:16:45 -07:00
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
rc = mca_bml_r2_endpoint_add_btl (proc, bml_endpoint, btl, btl_endpoints[p]);
|
|
|
|
if (OMPI_SUCCESS != rc) {
|
|
|
|
btl->btl_del_procs(btl, 1, (opal_proc_t**)&proc, &btl_endpoints[p]);
|
|
|
|
continue;
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
2015-08-31 14:57:55 -06:00
|
|
|
|
|
|
|
/* This BTL is in use, allow the progress registration */
|
|
|
|
btl_inuse++;
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
2014-11-14 13:16:45 -07:00
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
if (btl_inuse) {
|
|
|
|
mca_bml_r2_register_progress (btl);
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-31 14:57:55 -06:00
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
free(btl_endpoints);
|
|
|
|
|
|
|
|
/* iterate back through procs and compute metrics for registered r2s */
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t p = 0; p < n_new_procs ; ++p) {
|
|
|
|
mca_bml_base_endpoint_t *bml_endpoint =
|
|
|
|
(mca_bml_base_endpoint_t *) new_procs[p]->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML];
|
2005-08-12 02:41:14 +00:00
|
|
|
|
2005-08-15 15:19:07 +00:00
|
|
|
/* skip over procs w/ no btl's registered */
|
2015-08-31 14:57:55 -06:00
|
|
|
if (NULL != bml_endpoint) {
|
|
|
|
mca_bml_r2_compute_endpoint_metrics (bml_endpoint);
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-15 19:39:56 +00:00
|
|
|
|
2006-08-14 19:17:36 +00:00
|
|
|
/* see if we have a connection to everyone else */
|
2015-08-31 14:57:55 -06:00
|
|
|
for(size_t p = 0; p < n_new_procs ; ++p) {
|
2006-08-14 19:17:36 +00:00
|
|
|
ompi_proc_t *proc = new_procs[p];
|
|
|
|
|
2013-08-30 16:54:55 +00:00
|
|
|
if (NULL == proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML]) {
|
2006-08-14 19:17:36 +00:00
|
|
|
ret = OMPI_ERR_UNREACH;
|
2014-05-20 08:40:32 +00:00
|
|
|
if (mca_bml_r2.show_unreach_errors) {
|
2015-08-31 14:57:55 -06:00
|
|
|
opal_show_help("help-mca-bml-r2.txt", "unreachable proc", true,
|
George did the work and deserves all the credit for it. Ralph did the merge, and deserves whatever blame results from errors in it :-)
WHAT: Open our low-level communication infrastructure by moving all necessary components (btl/rcache/allocator/mpool) down in OPAL
All the components required for inter-process communications are currently deeply integrated in the OMPI layer. Several groups/institutions have express interest in having a more generic communication infrastructure, without all the OMPI layer dependencies. This communication layer should be made available at a different software level, available to all layers in the Open MPI software stack. As an example, our ORTE layer could replace the current OOB and instead use the BTL directly, gaining access to more reactive network interfaces than TCP. Similarly, external software libraries could take advantage of our highly optimized AM (active message) communication layer for their own purpose. UTK with support from Sandia, developped a version of Open MPI where the entire communication infrastucture has been moved down to OPAL (btl/rcache/allocator/mpool). Most of the moved components have been updated to match the new schema, with few exceptions (mainly BTLs where I have no way of compiling/testing them). Thus, the completion of this RFC is tied to being able to completing this move for all BTLs. For this we need help from the rest of the Open MPI community, especially those supporting some of the BTLs. A non-exhaustive list of BTLs that qualify here is: mx, portals4, scif, udapl, ugni, usnic.
This commit was SVN r32317.
2014-07-26 00:47:28 +00:00
|
|
|
OMPI_NAME_PRINT(&(ompi_proc_local_proc->super.proc_name)),
|
|
|
|
(NULL != ompi_proc_local_proc->super.proc_hostname ?
|
|
|
|
ompi_proc_local_proc->super.proc_hostname : "unknown!"),
|
|
|
|
OMPI_NAME_PRINT(&(proc->super.proc_name)),
|
2014-08-22 19:20:45 +00:00
|
|
|
(NULL != proc->super.proc_hostname ?
|
|
|
|
proc->super.proc_hostname : "unknown!"),
|
2014-05-20 08:40:32 +00:00
|
|
|
btl_names);
|
|
|
|
}
|
2015-08-31 14:57:55 -06:00
|
|
|
|
2014-05-20 08:40:32 +00:00
|
|
|
break;
|
2006-08-14 19:17:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-20 08:40:32 +00:00
|
|
|
free(new_procs);
|
2006-08-14 19:17:36 +00:00
|
|
|
|
|
|
|
return ret;
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-09-15 22:56:23 +00:00
|
|
|
* iterate through each proc and notify any BTLs associated
|
2005-08-12 02:41:14 +00:00
|
|
|
* with the proc that it is/has gone away
|
|
|
|
*/
|
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
static int mca_bml_r2_del_procs(size_t nprocs,
|
|
|
|
struct ompi_proc_t** procs)
|
2005-08-12 02:41:14 +00:00
|
|
|
{
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t p = 0 ; p < nprocs ; ++p) {
|
2015-06-23 20:59:57 -07:00
|
|
|
ompi_proc_t *proc = procs[p];
|
2015-09-23 10:45:13 -06:00
|
|
|
mca_bml_base_endpoint_t *bml_endpoint =
|
2013-08-30 16:54:55 +00:00
|
|
|
(mca_bml_base_endpoint_t*) proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML];
|
2015-09-23 10:45:13 -06:00
|
|
|
|
|
|
|
if (!bml_endpoint) {
|
|
|
|
/* NTH: I would think this is a developer bug and should not be ignored. */
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-20 08:46:57 +00:00
|
|
|
|
2008-09-15 22:56:23 +00:00
|
|
|
/* notify each btl that the proc is going away */
|
2015-09-23 10:45:13 -06:00
|
|
|
size_t f_size = mca_bml_base_btl_array_get_size (&bml_endpoint->btl_send);
|
2015-08-31 14:57:55 -06:00
|
|
|
for (size_t f_index = 0 ; f_index < f_size ; ++f_index) {
|
2014-05-20 08:46:57 +00:00
|
|
|
mca_bml_base_btl_t* bml_btl = mca_bml_base_btl_array_get_index(&bml_endpoint->btl_send, f_index);
|
2015-09-23 10:45:13 -06:00
|
|
|
mca_btl_base_module_t *btl = bml_btl->btl;
|
2014-05-20 08:46:57 +00:00
|
|
|
|
2015-09-23 10:45:13 -06:00
|
|
|
int rc = btl->btl_del_procs (btl, 1, (opal_proc_t **) &proc, &bml_btl->btl_endpoint);
|
|
|
|
if (OPAL_SUCCESS != rc) {
|
2005-08-12 02:41:14 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-05-20 08:53:22 +00:00
|
|
|
/* The reference stored in btl_eager and btl_rdma will automatically
|
|
|
|
* dissapear once the btl_array destructor is called. Thus, there is
|
|
|
|
* no need for extra cleaning here.
|
|
|
|
*/
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
2014-05-20 08:46:57 +00:00
|
|
|
|
2015-09-23 10:45:13 -06:00
|
|
|
/* some btl endpoints may only be in the btl_rdma array. call del_procs on those as well */
|
|
|
|
size_t r_size = mca_bml_base_btl_array_get_size (&bml_endpoint->btl_rdma);
|
|
|
|
for (size_t r_index = 0 ; r_index < r_size ; ++r_index) {
|
|
|
|
mca_bml_base_btl_t *rdma_btl = mca_bml_base_btl_array_get_index (&bml_endpoint->btl_rdma, r_index);
|
|
|
|
mca_btl_base_module_t *btl = rdma_btl->btl;
|
|
|
|
bool needs_del = true;
|
|
|
|
|
|
|
|
for (size_t f_index = 0 ; f_index < f_size ; ++f_index) {
|
|
|
|
mca_bml_base_btl_t *bml_btl = mca_bml_base_btl_array_get_index (&bml_endpoint->btl_send, f_index);
|
|
|
|
if (bml_btl->btl_endpoint == rdma_btl->btl_endpoint) {
|
|
|
|
needs_del = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needs_del) {
|
|
|
|
int rc = btl->btl_del_procs (btl, 1, (opal_proc_t **) &proc, &rdma_btl->btl_endpoint);
|
|
|
|
if (OPAL_SUCCESS != rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-31 14:57:55 -06:00
|
|
|
proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML] = NULL;
|
|
|
|
|
2015-09-23 10:45:13 -06:00
|
|
|
/* release the bml endpoint's reference to the proc */
|
2014-05-20 08:46:57 +00:00
|
|
|
OBJ_RELEASE(proc);
|
2015-08-31 14:57:55 -06:00
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
/* do any required cleanup */
|
|
|
|
OBJ_RELEASE(bml_endpoint);
|
|
|
|
}
|
2014-05-15 15:59:51 +00:00
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-09-17 13:55:21 +00:00
|
|
|
static inline int bml_r2_remove_btl_progress(mca_btl_base_module_t* btl)
|
2008-09-15 22:56:23 +00:00
|
|
|
{
|
|
|
|
unsigned int p;
|
|
|
|
|
|
|
|
if(NULL == btl->btl_component->btl_progress) {
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
for(p = 0; p < mca_bml_r2.num_btl_progress; p++) {
|
|
|
|
if(btl->btl_component->btl_progress != mca_bml_r2.btl_progress[p])
|
|
|
|
continue;
|
|
|
|
opal_progress_unregister( btl->btl_component->btl_progress );
|
2015-06-23 20:59:57 -07:00
|
|
|
if( p < (mca_bml_r2.num_btl_progress-1) ) {
|
2008-09-15 22:56:23 +00:00
|
|
|
mca_bml_r2.btl_progress[p] = mca_bml_r2.btl_progress[mca_bml_r2.num_btl_progress-1];
|
|
|
|
}
|
|
|
|
mca_bml_r2.num_btl_progress--;
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
return OMPI_ERR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
static int mca_bml_r2_del_proc_btl(ompi_proc_t* proc, mca_btl_base_module_t* btl)
|
|
|
|
{
|
2013-08-30 16:54:55 +00:00
|
|
|
mca_bml_base_endpoint_t* ep = (mca_bml_base_endpoint_t*)proc->proc_endpoints[OMPI_PROC_ENDPOINT_TAG_BML];
|
2008-09-30 21:02:37 +00:00
|
|
|
mca_bml_base_btl_t* bml_btl;
|
|
|
|
mca_btl_base_module_t* ep_btl;
|
2008-09-30 15:47:43 +00:00
|
|
|
double total_bandwidth = 0;
|
|
|
|
size_t b;
|
|
|
|
|
|
|
|
if(NULL == ep)
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
|
|
|
|
/* remove btl from eager list */
|
2009-08-05 22:23:26 +00:00
|
|
|
mca_bml_base_btl_array_remove(&ep->btl_eager, btl);
|
2015-06-23 20:59:57 -07:00
|
|
|
|
|
|
|
/* remove btl from send list */
|
|
|
|
if(mca_bml_base_btl_array_remove(&ep->btl_send, btl)) {
|
|
|
|
|
|
|
|
/* compute total_bandwidth and
|
2008-09-30 15:47:43 +00:00
|
|
|
reset max_send_size to the min of all btl's */
|
|
|
|
total_bandwidth = 0;
|
2011-01-04 20:35:33 +00:00
|
|
|
ep->btl_max_send_size = -1;
|
2008-09-30 15:47:43 +00:00
|
|
|
for(b=0; b< mca_bml_base_btl_array_get_size(&ep->btl_send); b++) {
|
2008-09-30 21:02:37 +00:00
|
|
|
bml_btl = mca_bml_base_btl_array_get_index(&ep->btl_send, b);
|
|
|
|
ep_btl = bml_btl->btl;
|
|
|
|
|
|
|
|
total_bandwidth += ep_btl->btl_bandwidth;
|
2011-01-04 20:35:33 +00:00
|
|
|
if (ep->btl_max_send_size > ep_btl->btl_max_send_size) {
|
2008-09-30 21:02:37 +00:00
|
|
|
ep->btl_max_send_size = ep_btl->btl_max_send_size;
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
/* compute weighting factor for this btl */
|
|
|
|
for(b=0; b< mca_bml_base_btl_array_get_size(&ep->btl_send); b++) {
|
2008-09-30 21:02:37 +00:00
|
|
|
bml_btl = mca_bml_base_btl_array_get_index(&ep->btl_send, b);
|
|
|
|
ep_btl = bml_btl->btl;
|
|
|
|
|
|
|
|
if(ep_btl->btl_bandwidth > 0) {
|
2008-11-24 15:53:56 +00:00
|
|
|
bml_btl->btl_weight = (float)(ep_btl->btl_bandwidth / total_bandwidth);
|
2008-09-30 15:47:43 +00:00
|
|
|
} else {
|
2008-11-24 15:53:56 +00:00
|
|
|
bml_btl->btl_weight = (float)(1.0 / mca_bml_base_btl_array_get_size(&ep->btl_send));
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove btl from RDMA list */
|
2015-06-23 20:59:57 -07:00
|
|
|
if(mca_bml_base_btl_array_remove(&ep->btl_rdma, btl)) {
|
|
|
|
|
2011-01-04 20:35:33 +00:00
|
|
|
/* compute total bandwidth */
|
2008-09-30 15:47:43 +00:00
|
|
|
total_bandwidth = 0;
|
2011-01-04 20:35:33 +00:00
|
|
|
ep->btl_pipeline_send_length = 0;
|
|
|
|
ep->btl_send_limit = 0;
|
2008-09-30 15:47:43 +00:00
|
|
|
for(b=0; b< mca_bml_base_btl_array_get_size(&ep->btl_rdma); b++) {
|
2008-09-30 21:02:37 +00:00
|
|
|
bml_btl = mca_bml_base_btl_array_get_index(&ep->btl_rdma, b);
|
|
|
|
ep_btl = bml_btl->btl;
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
/* update aggregate endpoint info */
|
2008-09-30 21:02:37 +00:00
|
|
|
total_bandwidth += ep_btl->btl_bandwidth;
|
|
|
|
if (ep->btl_pipeline_send_length < ep_btl->btl_rdma_pipeline_send_length) {
|
|
|
|
ep->btl_pipeline_send_length = ep_btl->btl_rdma_pipeline_send_length;
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
2008-09-30 21:02:37 +00:00
|
|
|
if (ep->btl_send_limit < ep_btl->btl_min_rdma_pipeline_size) {
|
|
|
|
ep->btl_send_limit = ep_btl->btl_min_rdma_pipeline_size;
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
/* compute weighting factor for this btl */
|
|
|
|
for(b=0; b< mca_bml_base_btl_array_get_size(&ep->btl_rdma); b++) {
|
2008-09-30 21:02:37 +00:00
|
|
|
bml_btl = mca_bml_base_btl_array_get_index(&ep->btl_rdma, b);
|
|
|
|
ep_btl = bml_btl->btl;
|
|
|
|
|
|
|
|
if(ep_btl->btl_bandwidth > 0) {
|
2008-11-24 15:53:56 +00:00
|
|
|
bml_btl->btl_weight = (float)(ep_btl->btl_bandwidth / total_bandwidth);
|
2008-09-30 15:47:43 +00:00
|
|
|
} else {
|
2008-11-24 15:53:56 +00:00
|
|
|
bml_btl->btl_weight = (float)(1.0 / mca_bml_base_btl_array_get_size(&ep->btl_rdma));
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2009-08-05 22:23:26 +00:00
|
|
|
return OMPI_SUCCESS;
|
2008-09-30 15:47:43 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 22:56:23 +00:00
|
|
|
int mca_bml_r2_finalize( void )
|
2015-06-23 20:59:57 -07:00
|
|
|
{
|
2007-02-21 16:18:43 +00:00
|
|
|
ompi_proc_t** procs;
|
|
|
|
size_t p, num_procs;
|
|
|
|
opal_list_item_t* w_item;
|
|
|
|
|
2008-09-11 20:52:58 +00:00
|
|
|
if (NULL != btl_names) {
|
|
|
|
free(btl_names);
|
|
|
|
btl_names = NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-21 16:18:43 +00:00
|
|
|
/* Similar to mca_bml_r2_del_btl ... */
|
|
|
|
procs = ompi_proc_all(&num_procs);
|
|
|
|
if(NULL == procs)
|
|
|
|
goto CLEANUP;
|
|
|
|
|
|
|
|
for (w_item = opal_list_get_first(&mca_btl_base_modules_initialized);
|
|
|
|
w_item != opal_list_get_end(&mca_btl_base_modules_initialized);
|
|
|
|
w_item = opal_list_get_next(w_item)) {
|
|
|
|
mca_btl_base_selected_module_t *sm = (mca_btl_base_selected_module_t *) w_item;
|
2008-09-15 22:56:23 +00:00
|
|
|
mca_btl_base_module_t* btl = sm->btl_module;
|
|
|
|
|
|
|
|
/* unregister the BTL progress function if any */
|
|
|
|
bml_r2_remove_btl_progress(btl);
|
2007-02-21 16:18:43 +00:00
|
|
|
|
|
|
|
/* dont use this btl for any peers */
|
2009-02-11 21:48:11 +00:00
|
|
|
for( p = 0; p < num_procs; p++ ) {
|
2007-02-21 16:18:43 +00:00
|
|
|
ompi_proc_t* proc = procs[p];
|
|
|
|
mca_bml_r2_del_proc_btl(proc, sm->btl_module);
|
|
|
|
}
|
|
|
|
}
|
2009-02-11 21:48:11 +00:00
|
|
|
/* Release the procs as the ompi_proc_all increase their ref_count */
|
|
|
|
for( p = 0; p < num_procs; p++ ) {
|
|
|
|
OBJ_RELEASE(procs[p]);
|
|
|
|
}
|
|
|
|
free(procs);
|
2007-02-21 16:18:43 +00:00
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
mca_bml_r2.num_btl_modules = 0;
|
|
|
|
mca_bml_r2.num_btl_progress = 0;
|
|
|
|
|
|
|
|
if( NULL != mca_bml_r2.btl_modules) {
|
2014-01-26 17:26:04 +00:00
|
|
|
free(mca_bml_r2.btl_modules);
|
2008-09-17 13:55:21 +00:00
|
|
|
mca_bml_r2.btl_modules = NULL;
|
2007-02-21 16:18:43 +00:00
|
|
|
}
|
|
|
|
if( NULL != mca_bml_r2.btl_progress ) {
|
2014-01-26 17:26:04 +00:00
|
|
|
free(mca_bml_r2.btl_progress);
|
2008-09-17 13:55:21 +00:00
|
|
|
mca_bml_r2.btl_progress = NULL;
|
2007-02-21 16:18:43 +00:00
|
|
|
}
|
|
|
|
|
2009-02-19 13:17:01 +00:00
|
|
|
/* Do not close the BTL base here; the BML upper layer will take
|
|
|
|
care of that. */
|
2007-02-21 16:18:43 +00:00
|
|
|
|
|
|
|
return OMPI_SUCCESS;
|
2015-06-23 20:59:57 -07:00
|
|
|
}
|
2005-08-12 02:41:14 +00:00
|
|
|
|
2006-03-27 22:48:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* (1) Remove btl from each bml endpoint
|
|
|
|
* (2) Remove btl from the global list
|
|
|
|
*/
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
static int mca_bml_r2_del_btl(mca_btl_base_module_t* btl)
|
2006-03-27 22:48:12 +00:00
|
|
|
{
|
|
|
|
ompi_proc_t** procs;
|
2008-09-15 22:56:23 +00:00
|
|
|
size_t i, m, p, num_procs;
|
2006-05-04 18:48:45 +00:00
|
|
|
opal_list_item_t* item;
|
|
|
|
mca_btl_base_module_t** modules;
|
2006-11-06 21:27:17 +00:00
|
|
|
bool found = false;
|
2015-06-23 20:59:57 -07:00
|
|
|
|
|
|
|
if(opal_list_get_size(&mca_btl_base_modules_initialized) == 2) {
|
2008-06-09 14:53:58 +00:00
|
|
|
opal_output(0, "only one BTL left, can't failover");
|
2009-02-11 21:48:11 +00:00
|
|
|
return OMPI_SUCCESS;
|
2006-11-06 21:27:17 +00:00
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2009-02-11 21:48:11 +00:00
|
|
|
procs = ompi_proc_all(&num_procs);
|
|
|
|
if(NULL == procs)
|
|
|
|
return OMPI_SUCCESS;
|
2015-06-23 20:59:57 -07:00
|
|
|
|
2008-09-15 22:56:23 +00:00
|
|
|
/* Get rid of the associated progress function */
|
|
|
|
bml_r2_remove_btl_progress(btl);
|
|
|
|
|
2006-05-04 18:48:45 +00:00
|
|
|
/* dont use this btl for any peers */
|
2008-09-15 22:56:23 +00:00
|
|
|
for( p = 0; p < num_procs; p++ ) {
|
2006-03-27 22:48:12 +00:00
|
|
|
ompi_proc_t* proc = procs[p];
|
2006-05-04 15:19:12 +00:00
|
|
|
mca_bml_r2_del_proc_btl(proc, btl);
|
|
|
|
}
|
2006-05-04 18:48:45 +00:00
|
|
|
|
|
|
|
/* remove from the btl list */
|
|
|
|
for (item = opal_list_get_first(&mca_btl_base_modules_initialized);
|
|
|
|
item != opal_list_get_end(&mca_btl_base_modules_initialized);
|
|
|
|
item = opal_list_get_next(item)) {
|
|
|
|
mca_btl_base_selected_module_t *sm = (mca_btl_base_selected_module_t *) item;
|
|
|
|
if(sm->btl_module == btl) {
|
|
|
|
opal_list_remove_item(&mca_btl_base_modules_initialized, item);
|
|
|
|
free(sm);
|
2006-11-06 21:27:17 +00:00
|
|
|
found = true;
|
2006-05-04 18:48:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-11-06 21:27:17 +00:00
|
|
|
if(!found) {
|
|
|
|
/* doesn't even exist */
|
2007-07-31 09:32:49 +00:00
|
|
|
goto CLEANUP;
|
2006-11-06 21:27:17 +00:00
|
|
|
}
|
2006-05-04 18:48:45 +00:00
|
|
|
/* remove from bml list */
|
2014-02-03 08:43:59 +00:00
|
|
|
modules = (mca_btl_base_module_t**)malloc(sizeof(mca_btl_base_module_t*) * (mca_bml_r2.num_btl_modules-1));
|
2006-05-04 18:48:45 +00:00
|
|
|
for(i=0,m=0; i<mca_bml_r2.num_btl_modules; i++) {
|
|
|
|
if(mca_bml_r2.btl_modules[i] != btl) {
|
|
|
|
modules[m++] = mca_bml_r2.btl_modules[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(mca_bml_r2.btl_modules);
|
|
|
|
mca_bml_r2.btl_modules = modules;
|
|
|
|
mca_bml_r2.num_btl_modules = m;
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
btl->btl_finalize(btl);
|
2007-07-31 09:34:41 +00:00
|
|
|
CLEANUP:
|
2009-02-11 21:48:11 +00:00
|
|
|
/* Decrease the ref_count increased by the call to ompi_proc_all */
|
|
|
|
for( p = 0; p < num_procs; p++ ) {
|
|
|
|
OBJ_RELEASE(procs[p]);
|
|
|
|
}
|
2006-05-04 15:19:12 +00:00
|
|
|
free(procs);
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
static int mca_bml_r2_add_btl(mca_btl_base_module_t* btl)
|
2006-03-27 22:48:12 +00:00
|
|
|
{
|
2011-10-04 14:50:31 +00:00
|
|
|
return OMPI_ERR_NOT_IMPLEMENTED;
|
2006-03-27 22:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register callback w/ all active btls
|
|
|
|
*/
|
2015-06-23 20:59:57 -07:00
|
|
|
static int mca_bml_r2_register( mca_btl_base_tag_t tag,
|
|
|
|
mca_btl_base_module_recv_cb_fn_t cbfunc,
|
2008-09-30 15:47:43 +00:00
|
|
|
void* data )
|
2005-08-12 02:41:14 +00:00
|
|
|
{
|
2008-01-15 05:32:53 +00:00
|
|
|
mca_btl_base_active_message_trigger[tag].cbfunc = cbfunc;
|
|
|
|
mca_btl_base_active_message_trigger[tag].cbdata = data;
|
|
|
|
/* Give an oportunity to the BTLs to do something special
|
|
|
|
* for each registration.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
int i, rc;
|
|
|
|
mca_btl_base_module_t *btl;
|
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
for(i = 0; i < (int)mca_bml_r2.num_btl_modules; i++) {
|
2008-01-15 05:32:53 +00:00
|
|
|
btl = mca_bml_r2.btl_modules[i];
|
|
|
|
if( NULL == btl->btl_register )
|
|
|
|
continue;
|
2015-06-23 20:59:57 -07:00
|
|
|
rc = btl->btl_register(btl, tag, cbfunc, data);
|
2008-01-15 05:32:53 +00:00
|
|
|
if(OMPI_SUCCESS != rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
2005-08-24 10:39:23 +00:00
|
|
|
}
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
2008-01-15 05:32:53 +00:00
|
|
|
|
2015-06-23 20:59:57 -07:00
|
|
|
return OMPI_SUCCESS;
|
2005-08-12 02:41:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-16 20:21:38 +00:00
|
|
|
/*
|
|
|
|
* Register an error handler with/ all active btls
|
|
|
|
* if they support error handlers..
|
|
|
|
*/
|
|
|
|
|
2008-09-30 15:47:43 +00:00
|
|
|
static int mca_bml_r2_register_error( mca_btl_base_module_error_cb_fn_t cbfunc)
|
2006-08-16 20:21:38 +00:00
|
|
|
{
|
2015-06-23 20:59:57 -07:00
|
|
|
uint32_t i;
|
2006-08-16 20:21:38 +00:00
|
|
|
int rc;
|
2015-06-23 20:59:57 -07:00
|
|
|
mca_btl_base_module_t *btl;
|
2006-08-17 22:02:01 +00:00
|
|
|
uint32_t ver;
|
2015-06-23 20:59:57 -07:00
|
|
|
|
|
|
|
for(i = 0; i < mca_bml_r2.num_btl_modules; i++) {
|
|
|
|
btl = mca_bml_r2.btl_modules[i];
|
|
|
|
/* this wont work for version numbers greater than 256... seems
|
2006-08-17 22:02:01 +00:00
|
|
|
reasonable.. */
|
|
|
|
ver = btl->btl_component->btl_version.mca_type_major_version << 16 |
|
|
|
|
btl->btl_component->btl_version.mca_type_minor_version << 8 |
|
|
|
|
btl->btl_component->btl_version.mca_type_release_version;
|
|
|
|
/* is version number greater than or equal to 1.0.1? */
|
2015-06-23 20:59:57 -07:00
|
|
|
if(ver >= ((1 << 16) | (0 << 8) | 1) &&
|
|
|
|
NULL != btl->btl_register_error) {
|
|
|
|
rc = btl->btl_register_error(btl, cbfunc);
|
2006-08-16 20:21:38 +00:00
|
|
|
if(OMPI_SUCCESS != rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-23 20:59:57 -07:00
|
|
|
return OMPI_SUCCESS;
|
2006-08-16 20:21:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-12 02:41:14 +00:00
|
|
|
int mca_bml_r2_component_fini(void)
|
|
|
|
{
|
|
|
|
return OMPI_SUCCESS;
|
|
|
|
}
|
2008-09-30 15:47:43 +00:00
|
|
|
|
|
|
|
mca_bml_r2_module_t mca_bml_r2 = {
|
2015-06-25 15:53:29 -07:00
|
|
|
.super = {
|
|
|
|
.bml_component = &mca_bml_r2_component,
|
2015-08-31 14:57:55 -06:00
|
|
|
.bml_add_proc = mca_bml_r2_add_proc,
|
2015-06-25 15:53:29 -07:00
|
|
|
.bml_add_procs = mca_bml_r2_add_procs,
|
|
|
|
.bml_del_procs = mca_bml_r2_del_procs,
|
|
|
|
.bml_add_btl = mca_bml_r2_add_btl,
|
|
|
|
.bml_del_btl = mca_bml_r2_del_btl,
|
|
|
|
.bml_del_proc_btl = mca_bml_r2_del_proc_btl,
|
|
|
|
.bml_register = mca_bml_r2_register,
|
|
|
|
.bml_register_error = mca_bml_r2_register_error,
|
|
|
|
.bml_finalize = mca_bml_r2_finalize,
|
2015-08-31 14:57:55 -06:00
|
|
|
.bml_ft_event = mca_bml_r2_ft_event,
|
|
|
|
},
|
2008-09-30 15:47:43 +00:00
|
|
|
};
|
|
|
|
|