839 строки
25 KiB
C
839 строки
25 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;
|
||
|
int param_tmp, param_value;
|
||
|
|
||
|
/*
|
||
|
* 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 ) {
|
||
|
param_tmp = mca_base_param_reg_int_name("rmaps", "ppr_pernode",
|
||
|
"Launch one ppn as directed",
|
||
|
false, false, (int)false, NULL);
|
||
|
mca_base_param_reg_syn_name(param_tmp, "rmaps", "base_pernode", false);
|
||
|
mca_base_param_lookup_int(param_tmp, ¶m_value);
|
||
|
if( param_value ) {
|
||
|
rmaps_lama_cmd_mppr = strdup("1:n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* -npernode X => -mppr X:n
|
||
|
*/
|
||
|
if( NULL == rmaps_lama_cmd_mppr ) {
|
||
|
param_tmp = mca_base_param_reg_int_name("rmaps", "ppr_n_pernode",
|
||
|
"Launch n procs/node",
|
||
|
false, false, (int)false, NULL);
|
||
|
mca_base_param_reg_syn_name(param_tmp, "rmaps", "base_n_pernode", false);
|
||
|
mca_base_param_lookup_int(param_tmp, ¶m_value);
|
||
|
if( param_value ) {
|
||
|
asprintf(&rmaps_lama_cmd_mppr, "%d:n", param_value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* -npersocket X => -mppr X:s
|
||
|
*/
|
||
|
if( NULL == rmaps_lama_cmd_mppr ) {
|
||
|
param_tmp = mca_base_param_reg_int_name("rmaps", "ppr_n_persocket",
|
||
|
"Launch n procs/socket",
|
||
|
false, false, (int)false, NULL);
|
||
|
mca_base_param_reg_syn_name(param_tmp, "rmaps", "base_n_persocket", false);
|
||
|
mca_base_param_lookup_int(param_tmp, ¶m_value);
|
||
|
if( param_value ) {
|
||
|
asprintf(&rmaps_lama_cmd_mppr, "%d:s", param_value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* -ppr => ~ -mppr
|
||
|
*/
|
||
|
if( NULL == rmaps_lama_cmd_mppr ) {
|
||
|
mca_base_param_reg_string_name("rmaps", "ppr_pattern",
|
||
|
"Comma-separated list of number of processes on a given resource type [default: none]",
|
||
|
false, false, NULL, &(jdata->map->ppr));
|
||
|
if( NULL != jdata->map->ppr ) {
|
||
|
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;
|
||
|
}
|
||
|
}
|