Skip to content

Commit bb835ff

Browse files
committed
mca/base: add a new MCA variable type for include lists
It is not uncommon in Open MPI to register a string variable to allow specifying an exclude or exclude list (every framework registers one). Given this common patten it is worthwhile to formalize an MCA include list variable type: MCA_BASE_VAR_TYPE_INCLUDE_LIST. Variables of this type use a new opal object (mca_base_var_include_list_t) that stores and argv-style array and an exclude- list flag. To register an include list variable the caller must first either OBJ_CONSTRUCT the object or allocate it with OBJ_NEW. Variables of this type are exposed as strings to MPI_T. Signed-off-by: Nathan Hjelm <hjelmn@google.com>
1 parent e4b98d7 commit bb835ff

15 files changed

+910
-26
lines changed

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,7 @@ AC_CONFIG_FILES([
15051505
test/asm/Makefile
15061506
test/datatype/Makefile
15071507
test/class/Makefile
1508+
test/mca/Makefile
15081509
test/mpool/Makefile
15091510
test/support/Makefile
15101511
test/threads/Makefile

ompi/mpi/tool/cvar_read.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* reserved.
1111
* Copyright (c) 2021 Amazon.com, Inc. or its affiliates. All Rights
1212
* reserved.
13+
* Copyright (c) 2024 Google, LLC. All rights reserved.
1314
* $COPYRIGHT$
1415
*
1516
* Additional copyrights may follow
@@ -88,6 +89,17 @@ int MPI_T_cvar_read (MPI_T_cvar_handle handle, void *buf)
8889
}
8990

9091
break;
92+
case MCA_BASE_VAR_TYPE_SERIALIZABLE: {
93+
char *tmp = value->serializable.serialize(&value->serializable);
94+
if (strlen(tmp) == 0) {
95+
((char *)buf)[0] = '\0';
96+
} else {
97+
strcpy ((char *) buf, tmp);
98+
}
99+
free (tmp);
100+
101+
break;
102+
}
91103
default:
92104
rc = MPI_T_ERR_INVALID;
93105
}

ompi/mpi/tool/mpit_common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Copyright (c) 2020 The University of Tennessee and The University
99
* of Tennessee Research Foundation. All rights
1010
* reserved.
11+
* Copyright (c) 2024 Google, LLC. All rights reserved.
1112
* $COPYRIGHT$
1213
*
1314
* Additional copyrights may follow
@@ -56,6 +57,7 @@ static MPI_Datatype mca_to_mpi_datatypes[MCA_BASE_VAR_TYPE_MAX] = {
5657
[MCA_BASE_VAR_TYPE_UINT32_T] = MPI_UINT32_T,
5758
[MCA_BASE_VAR_TYPE_INT64_T] = MPI_INT64_T,
5859
[MCA_BASE_VAR_TYPE_UINT64_T] = MPI_UINT64_T,
60+
[MCA_BASE_VAR_TYPE_SERIALIZABLE] = MPI_CHAR,
5961
};
6062

6163
int ompit_var_type_to_datatype (mca_base_var_type_t type, MPI_Datatype *datatype)

opal/class/Makefile.am

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# reserved.
1616
# Copyright (c) 2021 Nanook Consulting. All rights reserved.
1717
# Copyright (c) 2022 Amazon.com, Inc. or its affiliates. All Rights reserved.
18+
# Copyright (c) 2024 Google, LLC. All rights reserved.
1819
# $COPYRIGHT$
1920
#
2021
# Additional copyrights may follow
@@ -41,7 +42,9 @@ headers += \
4142
class/opal_value_array.h \
4243
class/opal_ring_buffer.h \
4344
class/opal_rb_tree.h \
44-
class/opal_interval_tree.h
45+
class/opal_interval_tree.h \
46+
class/opal_include_list.h \
47+
class/opal_serializable.h
4548

4649
libopen_pal_core_la_SOURCES += \
4750
class/opal_bitmap.c \
@@ -58,4 +61,6 @@ libopen_pal_core_la_SOURCES += \
5861
class/opal_value_array.c \
5962
class/opal_ring_buffer.c \
6063
class/opal_rb_tree.c \
61-
class/opal_interval_tree.c
64+
class/opal_interval_tree.c \
65+
class/opal_include_list.c \
66+
class/opal_serializable.c

opal/class/opal_include_list.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2+
/*
3+
* Copyright (c) 2024 Google, LLC. All rights reserved.
4+
* $COPYRIGHT$
5+
*
6+
* Additional copyrights may follow
7+
*
8+
* $HEADER$
9+
*/
10+
11+
#include <regex.h>
12+
13+
#include "opal_config.h"
14+
15+
#include "opal/class/opal_include_list.h"
16+
#include "opal/class/opal_object.h"
17+
#include "opal/include/opal/constants.h"
18+
#include "opal/mca/base/base.h"
19+
#include "opal/util/argv.h"
20+
#include "opal/util/output.h"
21+
#include "opal/util/printf.h"
22+
23+
static void include_list_destructor(opal_include_list_t *p);
24+
25+
static int opal_include_list_deserialize(opal_include_list_t *object, const char *value)
26+
{
27+
/* release any current value and set to defaults */
28+
include_list_destructor(object);
29+
30+
if (NULL == value || 0 == strlen(value)) {
31+
return OPAL_SUCCESS;
32+
}
33+
34+
if ('^' == value[0]) {
35+
object->is_exclude = true;
36+
++value;
37+
}
38+
39+
object->items = opal_argv_split(value, ',');
40+
return OPAL_SUCCESS;
41+
}
42+
43+
static char *opal_include_list_serialize(const opal_include_list_t *object)
44+
{
45+
if (NULL == object->items) {
46+
return strdup("");
47+
}
48+
49+
char *tmp = opal_argv_join(object->items, ',');
50+
if (object->is_exclude) {
51+
char *value_str = NULL;
52+
(void) opal_asprintf(&value_str, "^%s", tmp);
53+
free(tmp);
54+
return value_str;
55+
}
56+
57+
return tmp;
58+
}
59+
60+
static bool opal_include_list_is_set(const opal_include_list_t *object)
61+
{
62+
return (object->items != NULL);
63+
}
64+
65+
static void include_list_contructor(opal_include_list_t *p)
66+
{
67+
p->super.deserialize = (opal_serializable_deserialize_fn_t)opal_include_list_deserialize;
68+
p->super.serialize = (opal_serializable_serialize_fn_t)opal_include_list_serialize;
69+
p->super.is_set = (opal_serializable_is_set_fn_t)opal_include_list_is_set;
70+
p->items = NULL;
71+
p->is_exclude = false;
72+
}
73+
74+
static void include_list_destructor(opal_include_list_t *p)
75+
{
76+
opal_argv_free(p->items);
77+
include_list_contructor(p);
78+
}
79+
80+
OBJ_CLASS_INSTANCE(opal_include_list_t, opal_object_t, include_list_contructor,
81+
include_list_destructor);
82+
83+
static int include_list_match_regex(opal_include_list_t *include_list, const char *value,
84+
bool case_sensitive)
85+
{
86+
int regex_flags = REG_EXTENDED | REG_NOSUB;
87+
regex_t regex;
88+
89+
if (!case_sensitive) {
90+
regex_flags |= REG_ICASE;
91+
}
92+
93+
for (int i = 0 ; include_list->items[i] ; ++i) {
94+
int rc = regcomp(&regex, include_list->items[i], regex_flags);
95+
if (rc != 0) {
96+
/* incorrectly formatted regular expression */
97+
opal_output_verbose(MCA_BASE_VERBOSE_WARN, 0, "error compiling regular expression: %s, "
98+
"ignoring", include_list->items[i]);
99+
continue;
100+
}
101+
102+
rc = regexec(&regex, value, /*nmatch=*/0, /*pmatch=*/NULL, /*eflags=*/0);
103+
regfree(&regex);
104+
if (0 == rc) {
105+
return (include_list->is_exclude ? -1 : 1) * (i + 1);
106+
}
107+
}
108+
109+
return include_list->is_exclude ? 1 : -1;
110+
}
111+
112+
static int include_list_match(opal_include_list_t *include_list, const char *value,
113+
bool case_sensitive)
114+
{
115+
for (int i = 0 ; include_list->items[i] ; ++i) {
116+
bool match = false;
117+
if (case_sensitive) {
118+
if (0 == strcmp(include_list->items[i], value)) {
119+
match = true;
120+
}
121+
} else if (0 == strcasecmp(include_list->items[i], value)) {
122+
match = true;
123+
}
124+
125+
if (match) {
126+
return (include_list->is_exclude ? -1 : 1) * (i + 1);
127+
}
128+
}
129+
130+
return include_list->is_exclude ? 1 : -1;
131+
}
132+
133+
int opal_include_list_match(opal_include_list_t *include_list, const char *value,
134+
bool regex_match, bool case_sensitive)
135+
{
136+
if (include_list == NULL || value == NULL || include_list->items == NULL) {
137+
opal_output_verbose(MCA_BASE_VERBOSE_ERROR, 0, "error matching in include list");
138+
return -1;
139+
}
140+
141+
if (regex_match) {
142+
return include_list_match_regex(include_list, value, case_sensitive);
143+
}
144+
145+
return include_list_match(include_list, value, case_sensitive);
146+
}

opal/class/opal_include_list.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2+
/*
3+
* Copyright (c) 2024 Google, LLC. All rights reserved.
4+
* $COPYRIGHT$
5+
*
6+
* Additional copyrights may follow
7+
*
8+
* $HEADER$
9+
*/
10+
11+
#if !defined(OPAL_INCLUDE_LIST_H)
12+
#define OPAL_INCLUDE_LIST_H
13+
14+
#include "opal_config.h"
15+
#include "opal/class/opal_object.h"
16+
#include "opal/class/opal_serializable.h"
17+
18+
/**
19+
* An include list. These are strings of the form:
20+
* foo,bar,baz (include)
21+
* ^foo,bar,baz (exclude)
22+
*/
23+
struct opal_include_list {
24+
opal_serializable_t super;
25+
/** argv array of items */
26+
char **items;
27+
/** is this an exclude list */
28+
bool is_exclude;
29+
};
30+
typedef struct opal_include_list opal_include_list_t;
31+
32+
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_include_list_t);
33+
34+
/**
35+
* Match a string against the include list and return the list rank.
36+
*
37+
* @param[in] include_list Include list
38+
* @param[in] value Value to match
39+
* @param[in] regex_match Treat the entries in the include list as regular expressions
40+
* @param[in] case_sensitive Make matching case sensitive
41+
*
42+
* This method searches the include list for value. If an entry matches then the rank of the
43+
* include list match is returned. A negative number is returned if the list is an exclude
44+
* list.
45+
*/
46+
OPAL_DECLSPEC int opal_include_list_match(opal_include_list_t *include_list, const char *value,
47+
bool regex_match, bool case_sensitive);
48+
49+
50+
#endif /* OPAL_INCLUDE_LIST_H */

opal/class/opal_serializable.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2+
/*
3+
* Copyright (c) 2024 Google, LLC. All rights reserved.
4+
* $COPYRIGHT$
5+
*
6+
* Additional copyrights may follow
7+
*
8+
* $HEADER$
9+
*/
10+
11+
#include <regex.h>
12+
13+
#include "opal_config.h"
14+
15+
#include "opal/class/opal_include_list.h"
16+
#include "opal/class/opal_object.h"
17+
#include "opal/include/opal/constants.h"
18+
#include "opal/mca/base/base.h"
19+
#include "opal/util/argv.h"
20+
#include "opal/util/output.h"
21+
22+
static int opal_serializable_deserialize(opal_serializable_t *object, const char *value)
23+
{
24+
(void)object;
25+
(void)value;
26+
return OPAL_ERR_NOT_IMPLEMENTED;
27+
}
28+
29+
static char *opal_serializable_serialize(const opal_serializable_t *object)
30+
{
31+
(void)object;
32+
return NULL;
33+
}
34+
35+
static bool opal_serializable_is_set(const opal_serializable_t *object)
36+
{
37+
(void)object;
38+
return false;
39+
}
40+
41+
static void opal_serializable_constructor(opal_serializable_t *p)
42+
{
43+
p->deserialize = opal_serializable_deserialize;
44+
p->serialize = opal_serializable_serialize;
45+
p->is_set = opal_serializable_is_set;
46+
}
47+
48+
static void opal_serializable_destructor(opal_serializable_t *p)
49+
{
50+
}
51+
52+
OBJ_CLASS_INSTANCE(opal_serializable_t, opal_object_t, opal_serializable_constructor,
53+
opal_serializable_destructor);

opal/class/opal_serializable.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2+
/*
3+
* Copyright (c) 2024 Google, LLC. All rights reserved.
4+
* $COPYRIGHT$
5+
*
6+
* Additional copyrights may follow
7+
*
8+
* $HEADER$
9+
*/
10+
11+
#if !defined(OPAL_SERIALIZABLE_H)
12+
#define OPAL_SERIALIZABLE_H
13+
14+
#include "opal_config.h"
15+
#include "opal/class/opal_object.h"
16+
17+
struct opal_serializable;
18+
typedef struct opal_serializable opal_serializable_t;
19+
20+
typedef int (*opal_serializable_deserialize_fn_t)(opal_serializable_t *object, const char *value);
21+
typedef char *(*opal_serializable_serialize_fn_t)(const opal_serializable_t *object);
22+
typedef bool (*opal_serializable_is_set_fn_t)(const opal_serializable_t *object);
23+
24+
struct opal_serializable {
25+
opal_object_t super;
26+
/** de-serialize the object from a string */
27+
opal_serializable_deserialize_fn_t deserialize;
28+
/** serialize the object into a string */
29+
opal_serializable_serialize_fn_t serialize;
30+
/** object has a value set */
31+
opal_serializable_is_set_fn_t is_set;
32+
};
33+
34+
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_serializable_t);
35+
36+
#endif /* OPAL_SERIALIZABLE_H */

0 commit comments

Comments
 (0)