
Features: - Support for an override parameter file (openmpi-mca-param-override.conf). Variable values in this file can not be overridden by any file or environment value. - Support for boolean, unsigned, and unsigned long long variables. - Support for true/false values. - Support for enumerations on integer variables. - Support for MPIT scope, verbosity, and binding. - Support for command line source. - Support for setting variable source via the environment using OMPI_MCA_SOURCE_<var name>=source (either command or file:filename) - Cleaner API. - Support for variable groups (equivalent to MPIT categories). Notes: - Variables must be created with a backing store (char **, int *, or bool *) that must live at least as long as the variable. - Creating a variable with the MCA_BASE_VAR_FLAG_SETTABLE enables the use of mca_base_var_set_value() to change the value. - String values are duplicated when the variable is registered. It is up to the caller to free the original value if necessary. The new value will be freed by the mca_base_var system and must not be freed by the user. - Variables with constant scope may not be settable. - Variable groups (and all associated variables) are deregistered when the component is closed or the component repository item is freed. This prevents a segmentation fault from accessing a variable after its component is unloaded. - After some discussion we decided we should remove the automatic registration of component priority variables. Few component actually made use of this feature. - The enumerator interface was updated to be general enough to handle future uses of the interface. - The code to generate ompi_info output has been moved into the MCA variable system. See mca_base_var_dump(). opal: update core and components to mca_base_var system orte: update core and components to mca_base_var system ompi: update core and components to mca_base_var system This commit also modifies the rmaps framework. The following variables were moved from ppr and lama: rmaps_base_pernode, rmaps_base_n_pernode, rmaps_base_n_persocket. Both lama and ppr create synonyms for these variables. This commit was SVN r28236.
812 строки
23 KiB
C
812 строки
23 KiB
C
/*
|
|
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
|
*
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
/**
|
|
* Processing for command line interface options
|
|
*
|
|
*/
|
|
#include "rmaps_lama.h"
|
|
|
|
#include "orte/mca/rmaps/base/rmaps_private.h"
|
|
#include "orte/mca/rmaps/base/base.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
/*********************************
|
|
* Local Functions
|
|
*********************************/
|
|
/*
|
|
* QSort: Integer comparison
|
|
*/
|
|
static int lama_parse_int_sort(const void *a, const void *b);
|
|
|
|
/*
|
|
* Convert the '-ppr' syntax from the 'ppr' component to the 'lama' '-mppr' syntax.
|
|
*/
|
|
static char * rmaps_lama_covert_ppr(char * given_ppr);
|
|
|
|
/*********************************
|
|
* Parsing Functions
|
|
*********************************/
|
|
int rmaps_lama_process_alias_params(orte_job_t *jdata)
|
|
{
|
|
int exit_status = ORTE_SUCCESS;
|
|
|
|
/*
|
|
* Mapping options
|
|
* Note: L1, L2, L3 are not exposed in orterun to the user, so
|
|
* there is no need to specify them here.
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_map ) {
|
|
/* orte_rmaps_base.mapping */
|
|
switch( ORTE_GET_MAPPING_POLICY(jdata->map->mapping) ) {
|
|
case ORTE_MAPPING_BYNODE:
|
|
/* rmaps_lama_cmd_map = strdup("nbNsL3L2L1ch"); */
|
|
rmaps_lama_cmd_map = strdup("nbsch");
|
|
break;
|
|
case ORTE_MAPPING_BYBOARD:
|
|
/* rmaps_lama_cmd_map = strdup("bnNsL3L2L1ch"); */
|
|
opal_output(0, "mca:rmaps:lama: ERROR: Unsupported Mapping Option!");
|
|
exit_status = ORTE_ERR_NOT_SUPPORTED;
|
|
goto cleanup;
|
|
break;
|
|
case ORTE_MAPPING_BYNUMA:
|
|
/* rmaps_lama_cmd_map = strdup("NbnsL3L2L1ch"); */
|
|
rmaps_lama_cmd_map = strdup("Nbnsch");
|
|
break;
|
|
case ORTE_MAPPING_BYSOCKET:
|
|
/* rmaps_lama_cmd_map = strdup("sNbnL3L2L1ch"); */
|
|
rmaps_lama_cmd_map = strdup("sbnch");
|
|
break;
|
|
case ORTE_MAPPING_BYL3CACHE:
|
|
rmaps_lama_cmd_map = strdup("L3sNbnL2L1ch");
|
|
break;
|
|
case ORTE_MAPPING_BYL2CACHE:
|
|
rmaps_lama_cmd_map = strdup("L2sNbnL1ch");
|
|
break;
|
|
case ORTE_MAPPING_BYL1CACHE:
|
|
rmaps_lama_cmd_map = strdup("L1sNbnch");
|
|
break;
|
|
case ORTE_MAPPING_BYCORE:
|
|
case ORTE_MAPPING_BYSLOT:
|
|
/* rmaps_lama_cmd_map = strdup("cL1L2L3sNbnh"); */
|
|
rmaps_lama_cmd_map = strdup("csbnh");
|
|
break;
|
|
case ORTE_MAPPING_BYHWTHREAD:
|
|
/* rmaps_lama_cmd_map = strdup("hcL1L2L3sNbn"); */
|
|
rmaps_lama_cmd_map = strdup("hcsbn");
|
|
break;
|
|
case ORTE_MAPPING_RR:
|
|
case ORTE_MAPPING_SEQ:
|
|
case ORTE_MAPPING_BYUSER:
|
|
opal_output(0, "mca:rmaps:lama: ERROR: Unsupported Mapping Option!");
|
|
exit_status = ORTE_ERR_NOT_SUPPORTED;
|
|
goto cleanup;
|
|
default:
|
|
/*
|
|
* Default is map-by core
|
|
*/
|
|
rmaps_lama_cmd_map = strdup("cL1L2L3sNbnh");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Binding Options
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_bind ) {
|
|
/*
|
|
* No binding specified, use default
|
|
*/
|
|
if( !OPAL_BINDING_POLICY_IS_SET(jdata->map->binding) ||
|
|
!OPAL_BINDING_REQUIRED(opal_hwloc_binding_policy) ||
|
|
OPAL_BIND_TO_NONE == OPAL_GET_BINDING_POLICY(jdata->map->binding) ) {
|
|
rmaps_lama_cmd_bind = NULL;
|
|
}
|
|
|
|
switch( OPAL_GET_BINDING_POLICY(jdata->map->binding) ) {
|
|
case OPAL_BIND_TO_BOARD:
|
|
/* rmaps_lama_cmd_bind = strdup("1b"); */
|
|
opal_output(0, "mca:rmaps:lama: ERROR: Unsupported Binding Option!");
|
|
exit_status = ORTE_ERR_NOT_SUPPORTED;
|
|
goto cleanup;
|
|
break;
|
|
case OPAL_BIND_TO_NUMA:
|
|
rmaps_lama_cmd_bind = strdup("1N");
|
|
break;
|
|
case OPAL_BIND_TO_SOCKET:
|
|
rmaps_lama_cmd_bind = strdup("1s");
|
|
break;
|
|
case OPAL_BIND_TO_L3CACHE:
|
|
rmaps_lama_cmd_bind = strdup("1L3");
|
|
break;
|
|
case OPAL_BIND_TO_L2CACHE:
|
|
rmaps_lama_cmd_bind = strdup("1L2");
|
|
break;
|
|
case OPAL_BIND_TO_L1CACHE:
|
|
rmaps_lama_cmd_bind = strdup("1L1");
|
|
break;
|
|
case OPAL_BIND_TO_CORE:
|
|
rmaps_lama_cmd_bind = strdup("1c");
|
|
break;
|
|
case OPAL_BIND_TO_HWTHREAD:
|
|
rmaps_lama_cmd_bind = strdup("1h");
|
|
break;
|
|
case OPAL_BIND_TO_CPUSET:
|
|
opal_output(0, "mca:rmaps:lama: ERROR: Unsupported Binding Option!");
|
|
exit_status = ORTE_ERR_NOT_SUPPORTED;
|
|
goto cleanup;
|
|
break;
|
|
default:
|
|
rmaps_lama_cmd_bind = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Ordering (a.k.a. Ranking) Options
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_ordering ) {
|
|
/* orte_rmaps_base.ranking */
|
|
switch( ORTE_GET_RANKING_POLICY(jdata->map->ranking) ) {
|
|
case ORTE_RANK_BY_SLOT:
|
|
rmaps_lama_cmd_ordering = strdup("s");
|
|
break;
|
|
case ORTE_RANK_BY_NODE:
|
|
case ORTE_RANK_BY_NUMA:
|
|
case ORTE_RANK_BY_SOCKET:
|
|
case ORTE_RANK_BY_L3CACHE:
|
|
case ORTE_RANK_BY_L2CACHE:
|
|
case ORTE_RANK_BY_L1CACHE:
|
|
case ORTE_RANK_BY_CORE:
|
|
case ORTE_RANK_BY_HWTHREAD:
|
|
rmaps_lama_cmd_ordering = strdup("n");
|
|
break;
|
|
case ORTE_RANK_BY_BOARD:
|
|
/* rmaps_lama_cmd_ordering = strdup("n"); */
|
|
opal_output(0, "mca:rmaps:lama: ERROR: Unsupported Ordering/Ranking Option!");
|
|
exit_status = ORTE_ERR_NOT_SUPPORTED;
|
|
goto cleanup;
|
|
break;
|
|
default:
|
|
rmaps_lama_cmd_ordering = strdup("n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* MPPR
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_mppr ) {
|
|
/*
|
|
* Take what the user specified as the -ppr
|
|
*/
|
|
if( NULL != jdata->map->ppr) {
|
|
rmaps_lama_cmd_mppr = rmaps_lama_covert_ppr(jdata->map->ppr);
|
|
}
|
|
/*
|
|
* Otherwise look at the parameters registered for the ppn component
|
|
*/
|
|
else {
|
|
/*
|
|
* -pernode => -mppr 1:n
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_mppr && orte_rmaps_base_pernode ) {
|
|
rmaps_lama_cmd_mppr = strdup("1:n");
|
|
}
|
|
|
|
/*
|
|
* -npernode X => -mppr X:n
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_mppr && orte_rmaps_base_n_pernode > 0) {
|
|
asprintf(&rmaps_lama_cmd_mppr, "%d:n", orte_rmaps_base_n_pernode);
|
|
}
|
|
|
|
/*
|
|
* -npersocket X => -mppr X:s
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_mppr && orte_rmaps_base_n_persocket > 0) {
|
|
asprintf(&rmaps_lama_cmd_mppr, "%d:s", orte_rmaps_base_n_persocket);
|
|
}
|
|
|
|
/*
|
|
* -ppr => ~ -mppr
|
|
*/
|
|
if( NULL == rmaps_lama_cmd_mppr && NULL != orte_rmaps_base_pattern ) {
|
|
jdata->map->ppr = strdup (orte_rmaps_base_pattern);
|
|
rmaps_lama_cmd_mppr = rmaps_lama_covert_ppr(jdata->map->ppr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Oversubscription
|
|
*/
|
|
if( ORTE_MAPPING_NO_OVERSUBSCRIBE & ORTE_GET_MAPPING_DIRECTIVE(jdata->map->mapping) ) {
|
|
rmaps_lama_can_oversubscribe = false;
|
|
}
|
|
else {
|
|
rmaps_lama_can_oversubscribe = true;
|
|
}
|
|
|
|
/*
|
|
* Display revised values
|
|
*/
|
|
opal_output_verbose(5, orte_rmaps_base.rmaps_output,
|
|
"mca:rmaps:lama: Revised Parameters -----");
|
|
opal_output_verbose(5, orte_rmaps_base.rmaps_output,
|
|
"mca:rmaps:lama: Map : %s",
|
|
rmaps_lama_cmd_map);
|
|
opal_output_verbose(5, orte_rmaps_base.rmaps_output,
|
|
"mca:rmaps:lama: Bind : %s",
|
|
rmaps_lama_cmd_bind);
|
|
opal_output_verbose(5, orte_rmaps_base.rmaps_output,
|
|
"mca:rmaps:lama: MPPR : %s",
|
|
rmaps_lama_cmd_mppr);
|
|
opal_output_verbose(5, orte_rmaps_base.rmaps_output,
|
|
"mca:rmaps:lama: Order : %s",
|
|
rmaps_lama_cmd_ordering);
|
|
|
|
|
|
cleanup:
|
|
return exit_status;
|
|
}
|
|
|
|
static char * rmaps_lama_covert_ppr(char * given_ppr)
|
|
{
|
|
return strdup(given_ppr);
|
|
}
|
|
|
|
int rmaps_lama_parse_mapping(char *layout,
|
|
rmaps_lama_level_type_t **layout_types,
|
|
rmaps_lama_level_type_t **layout_types_sorted,
|
|
int *num_types)
|
|
{
|
|
int exit_status = ORTE_SUCCESS;
|
|
char param[3];
|
|
int i, j, len;
|
|
bool found_req_param_n = false;
|
|
bool found_req_param_h = false;
|
|
bool found_req_param_bind = false;
|
|
|
|
/*
|
|
* Sanity Check:
|
|
* There is no default layout, so if we get here and nothing is specified
|
|
* then this is an error.
|
|
*/
|
|
if( NULL == layout ) {
|
|
return ORTE_ERROR;
|
|
}
|
|
|
|
*num_types = 0;
|
|
|
|
/*
|
|
* Extract and convert all the keys
|
|
*/
|
|
len = strlen(layout);
|
|
for(i = 0; i < len; ++i) {
|
|
/*
|
|
* L1 : L1 Cache
|
|
* L2 : L2 Cache
|
|
* L3 : L3 Cache
|
|
*/
|
|
if( layout[i] == 'L' ) {
|
|
param[0] = layout[i];
|
|
++i;
|
|
/*
|
|
* Check for 2 characters
|
|
*/
|
|
if( i >= len ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Cache Level must be followed by a number [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
param[1] = layout[i];
|
|
param[2] = '\0';
|
|
}
|
|
/*
|
|
* n : Machine
|
|
* b : Board
|
|
* s : Socket
|
|
* c : Core
|
|
* h : Hardware Thread
|
|
* N : NUMA Node
|
|
*/
|
|
else {
|
|
param[0] = layout[i];
|
|
param[1] = '\0';
|
|
}
|
|
|
|
/*
|
|
* Append level
|
|
*/
|
|
*num_types += 1;
|
|
*layout_types = (rmaps_lama_level_type_t*)realloc(*layout_types, sizeof(rmaps_lama_level_type_t) * (*num_types));
|
|
(*layout_types)[(*num_types)-1] = lama_type_str_to_enum(param);
|
|
}
|
|
|
|
/*
|
|
* Check for duplicates and unknowns
|
|
* Copy to sorted list
|
|
*/
|
|
*layout_types_sorted = (rmaps_lama_level_type_t*)malloc(sizeof(rmaps_lama_level_type_t) * (*num_types));
|
|
for( i = 0; i < *num_types; ++i ) {
|
|
/*
|
|
* Copy for later sorting
|
|
*/
|
|
(*layout_types_sorted)[i] = (*layout_types)[i];
|
|
|
|
/*
|
|
* Look for unknown and unsupported options
|
|
*/
|
|
if( LAMA_LEVEL_UNKNOWN <= (*layout_types)[i] ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Unknown or Unsupported option in layout [%s] position %d!",
|
|
layout, i+1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( LAMA_LEVEL_MACHINE == (*layout_types)[i] ) {
|
|
found_req_param_n = true;
|
|
}
|
|
|
|
if( LAMA_LEVEL_PU == (*layout_types)[i] ) {
|
|
found_req_param_h = true;
|
|
}
|
|
|
|
if( lama_binding_level == (*layout_types)[i] ) {
|
|
found_req_param_bind = true;
|
|
}
|
|
|
|
/*
|
|
* Look for duplicates
|
|
*/
|
|
for( j = i+1; j < *num_types; ++j ) {
|
|
if( (*layout_types)[i] == (*layout_types)[j] ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Duplicate key detected in layout [%s] position %d and %d!",
|
|
layout, i+1, j+1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The user is required to specify at least the:
|
|
* - machine
|
|
* - hardware thread (needed for lower bound binding) JJH: We should be able to lift this...
|
|
* - binding layer (need it to stride the mapping)
|
|
*/
|
|
if( !found_req_param_n ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Required level not specified 'n' in layout [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
if( !found_req_param_h ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Required level not specified 'h' in layout [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
if( !found_req_param_bind ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Required binding level [%s] not specified in mapping layout [%s]!",
|
|
rmaps_lama_cmd_bind, layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
/*
|
|
* Sort the items
|
|
*/
|
|
qsort((*layout_types_sorted ), (*num_types), sizeof(int), lama_parse_int_sort);
|
|
|
|
|
|
cleanup:
|
|
return exit_status;
|
|
}
|
|
|
|
int rmaps_lama_parse_binding(char *layout, rmaps_lama_level_type_t *binding_level, int *num_types)
|
|
{
|
|
int exit_status = ORTE_SUCCESS;
|
|
char param[3];
|
|
char num[MAX_BIND_DIGIT_LEN];
|
|
int i, n, p, len;
|
|
|
|
/*
|
|
* Default: If nothing specified
|
|
* - Bind to machine
|
|
*/
|
|
if( NULL == layout ) {
|
|
*binding_level = LAMA_LEVEL_MACHINE;
|
|
*num_types = 1;
|
|
return ORTE_SUCCESS;
|
|
}
|
|
|
|
*num_types = 0;
|
|
|
|
/*
|
|
* Extract and convert all the keys
|
|
*/
|
|
len = strlen(layout);
|
|
n = 0;
|
|
p = 0;
|
|
for(i = 0; i < len; ++i) {
|
|
/*
|
|
* Must start with a digit
|
|
*/
|
|
if( isdigit(layout[i]) ) {
|
|
/*
|
|
* Check: Digits must come first
|
|
*/
|
|
if( p != 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Binding: Digits must only come before Level string [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
num[n] = layout[i];
|
|
++n;
|
|
/*
|
|
* Check: Exceed bound of number of digits
|
|
*/
|
|
if( n >= MAX_BIND_DIGIT_LEN ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Binding: Too many digits in [%s]! Limit %d",
|
|
layout, MAX_BIND_DIGIT_LEN-1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
/*
|
|
* Extract the level
|
|
*/
|
|
else {
|
|
/*
|
|
* Check: Digits must come first
|
|
*/
|
|
if( n == 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Binding: Digits must come before Level string [%s] [%c]!",
|
|
layout, layout[i]);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
/*
|
|
* Check: Only one level allowed
|
|
*/
|
|
if( p != 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Binding: Only one level may be specified [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
/*
|
|
* L1 : L1 Cache
|
|
* L2 : L2 Cache
|
|
* L3 : L3 Cache
|
|
*/
|
|
if( layout[i] == 'L' ) {
|
|
param[0] = layout[i];
|
|
++i;
|
|
/*
|
|
* Check for 2 characters
|
|
*/
|
|
if( i >= len ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Cache Level must be followed by a number [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
param[1] = layout[i];
|
|
p = 2;
|
|
}
|
|
/*
|
|
* n : Machine
|
|
* b : Board
|
|
* s : Socket
|
|
* c : Core
|
|
* h : Hardware Thread
|
|
* N : NUMA Node
|
|
*/
|
|
else {
|
|
param[0] = layout[i];
|
|
p = 1;
|
|
}
|
|
param[p] = '\0';
|
|
}
|
|
}
|
|
/*
|
|
* Check that the level was specified
|
|
*/
|
|
if( p == 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Binding: Level not specified [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
num[n] = '\0';
|
|
|
|
*binding_level = lama_type_str_to_enum(param);
|
|
*num_types = atoi(num);
|
|
|
|
/*
|
|
* Check for unknown level
|
|
*/
|
|
if( LAMA_LEVEL_UNKNOWN <= *binding_level ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Unknown or Unsupported option in layout [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
return exit_status;
|
|
}
|
|
|
|
int rmaps_lama_parse_mppr(char *layout, rmaps_lama_level_info_t **mppr_levels, int *num_types)
|
|
{
|
|
int exit_status = ORTE_SUCCESS;
|
|
char param[3];
|
|
char num[MAX_BIND_DIGIT_LEN];
|
|
char **argv = NULL;
|
|
int argc = 0;
|
|
int i, j, len;
|
|
int p, n;
|
|
|
|
/*
|
|
* Default: Unrestricted allocation
|
|
* 'oversubscribe' flag accounted for elsewhere
|
|
*/
|
|
if( NULL == layout ) {
|
|
*mppr_levels = NULL;
|
|
*num_types = 0;
|
|
return ORTE_SUCCESS;
|
|
}
|
|
|
|
*num_types = 0;
|
|
|
|
/*
|
|
* Split by ','
|
|
* <#:level>,<#:level>,...
|
|
*/
|
|
argv = opal_argv_split(layout, ',');
|
|
argc = opal_argv_count(argv);
|
|
for(j = 0; j < argc; ++j) {
|
|
/*
|
|
* Parse <#:level>
|
|
*/
|
|
len = strlen(argv[j]);
|
|
n = 0;
|
|
p = 0;
|
|
for(i = 0; i < len; ++i) {
|
|
/*
|
|
* Skip the ':' separator and whitespace
|
|
*/
|
|
if( argv[j][i] == ':' || isblank(argv[j][i])) {
|
|
continue;
|
|
}
|
|
/*
|
|
* Must start with a digit
|
|
*/
|
|
else if( isdigit(argv[j][i]) ) {
|
|
/*
|
|
* Check: Digits must come first
|
|
*/
|
|
if( p != 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Digits must only come before Level string [%s] at [%s]!",
|
|
layout, argv[j]);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
num[n] = argv[j][i];
|
|
++n;
|
|
/*
|
|
* Check: Exceed bound of number of digits
|
|
*/
|
|
if( n >= MAX_BIND_DIGIT_LEN ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Too many digits in [%s]! Limit %d",
|
|
argv[j], MAX_BIND_DIGIT_LEN-1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
/*
|
|
* Extract the level
|
|
*/
|
|
else {
|
|
/*
|
|
* Check: Digits must come first
|
|
*/
|
|
if( n == 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Digits must come before Level string [%s]!",
|
|
argv[j]);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
/*
|
|
* Check: Only one level allowed
|
|
*/
|
|
if( p != 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Only one level may be specified [%s]!",
|
|
argv[j]);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
/*
|
|
* L1 : L1 Cache
|
|
* L2 : L2 Cache
|
|
* L3 : L3 Cache
|
|
*/
|
|
if( argv[j][i] == 'L' ) {
|
|
param[0] = argv[j][i];
|
|
++i;
|
|
/*
|
|
* Check for 2 characters
|
|
*/
|
|
if( i >= len ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Cache Level must be followed by a number [%s]!",
|
|
argv[j]);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
param[1] = argv[j][i];
|
|
p = 2;
|
|
}
|
|
/*
|
|
* n : Machine
|
|
* b : Board
|
|
* s : Socket
|
|
* c : Core
|
|
* h : Hardware Thread
|
|
* N : NUMA Node
|
|
*/
|
|
else {
|
|
param[0] = argv[j][i];
|
|
p = 1;
|
|
}
|
|
param[p] = '\0';
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Whitespace, just skip
|
|
*/
|
|
if( n == 0 && p == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Check that the level was specified
|
|
*/
|
|
if( p == 0 ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: MPPR: Level not specified [%s]!",
|
|
layout);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
num[n] = '\0';
|
|
|
|
/*
|
|
* Append level
|
|
*/
|
|
*num_types += 1;
|
|
*mppr_levels = (rmaps_lama_level_info_t*)realloc(*mppr_levels, sizeof(rmaps_lama_level_info_t) * (*num_types));
|
|
(*mppr_levels)[(*num_types)-1].type = lama_type_str_to_enum(param);
|
|
(*mppr_levels)[(*num_types)-1].max_resources = atoi(num);
|
|
|
|
}
|
|
|
|
/*
|
|
* Check for duplicates and unknowns
|
|
*/
|
|
for( i = 0; i < *num_types; ++i ) {
|
|
/*
|
|
* Look for unknown and unsupported options
|
|
*/
|
|
if( LAMA_LEVEL_UNKNOWN <= (*mppr_levels)[i].type ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Unknown or Unsupported option in layout [%s] position %d!",
|
|
layout, i+1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
|
|
/*
|
|
* Look for duplicates
|
|
*/
|
|
for( j = i+1; j < *num_types; ++j ) {
|
|
if( (*mppr_levels)[i].type == (*mppr_levels)[j].type ) {
|
|
opal_output(0, "mca:rmaps:lama: Error: Duplicate key detected in layout [%s] position %d and %d!",
|
|
layout, i+1, j+1);
|
|
exit_status = ORTE_ERROR;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if( NULL != argv ) {
|
|
opal_argv_free(argv);
|
|
argv = NULL;
|
|
}
|
|
|
|
return exit_status;
|
|
}
|
|
|
|
int rmaps_lama_parse_ordering(char *layout,
|
|
rmaps_lama_order_type_t *order)
|
|
{
|
|
/*
|
|
* Default: Natural ordering
|
|
*/
|
|
if( NULL == layout ) {
|
|
*order = LAMA_ORDER_NATURAL;
|
|
return ORTE_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Sequential Ordering
|
|
*/
|
|
if( 0 == strncmp(layout, "s", strlen("s")) ||
|
|
0 == strncmp(layout, "S", strlen("S")) ) {
|
|
*order = LAMA_ORDER_SEQ;
|
|
}
|
|
/*
|
|
* Natural Ordering
|
|
*/
|
|
else if( 0 == strncmp(layout, "n", strlen("n")) ||
|
|
0 == strncmp(layout, "N", strlen("N")) ) {
|
|
*order = LAMA_ORDER_NATURAL;
|
|
}
|
|
/*
|
|
* Check for unknown options
|
|
*/
|
|
else {
|
|
opal_output(0, "mca:rmaps:lama: Error: Unknown or Unsupported option in ordering [%s]!",
|
|
layout);
|
|
return ORTE_ERROR;
|
|
}
|
|
|
|
return ORTE_SUCCESS;
|
|
}
|
|
|
|
bool rmaps_lama_ok_to_prune_level(rmaps_lama_order_type_t level)
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < lama_mapping_num_layouts; ++i ) {
|
|
if( level == lama_mapping_layout[i] ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*********************************
|
|
* Support Functions
|
|
*********************************/
|
|
static int lama_parse_int_sort(const void *a, const void *b) {
|
|
int left = *((int*)a);
|
|
int right = *((int*)b);
|
|
|
|
if( left < right ) {
|
|
return -1;
|
|
}
|
|
else if( left > right ) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|