File: system_hints.c

package info (click to toggle)
openmpi 5.0.8-3
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 201,692 kB
  • sloc: ansic: 613,078; makefile: 42,353; sh: 11,194; javascript: 9,244; f90: 7,052; java: 6,404; perl: 5,179; python: 1,859; lex: 740; fortran: 61; cpp: 20; tcl: 12
file content (198 lines) | stat: -rw-r--r-- 5,961 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#include <adio.h>

#include <stdio.h>

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_IO_H
#include <io.h>
#endif

/*#define SYSHINT_DEBUG 1  */

#define ROMIO_HINT_DEFAULT_CFG "/etc/romio-hints"
#define ROMIO_HINT_ENV_VAR "ROMIO_HINTS"

/* debug function: a routine I want in the library to make my life easier when
 * using a source debugger.  Now optionally used in ADIO_Open. */
void ADIOI_Info_print_keyvals(MPI_Info info)
{
    int i, nkeys, flag;
    char key[MPI_MAX_INFO_KEY + 1];
    char value[MPI_MAX_INFO_VAL + 1];

    if (info == MPI_INFO_NULL)
        return;

    MPI_Info_get_nkeys(info, &nkeys);

    for (i = 0; i < nkeys; i++) {
        MPI_Info_get_nthkey(info, i, key);
        ADIOI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag);
        printf("key = %-25s value = %-10s\n", key, value);
    }
    return;
}

/* if user set the environment variable, use its value to find the
 * file-of-hints.  Otherwise, we'll look for the default config file.  i.e. let
 * the user override systemwide hint processing */

static int find_file(void)
{
    int fd = -1;
    char *hintfile;

    hintfile = getenv(ROMIO_HINT_ENV_VAR);
    if (hintfile)
        fd = open(hintfile, O_RDONLY);
    if (fd < 0)
        fd = open(ROMIO_HINT_DEFAULT_CFG, O_RDONLY);

    return fd;
}

/* parse the file-of-hints.  Format is zero or more lines of "<key> <value>\n".
 * A # in collumn zero is a comment and the line will be ignored.  Do our best
 * to ignore badly formed lines too.
 *
 * The caller provides an 'info' object.  Each key-value pair found by the
 * parser will get added to the info object.  any keys already set will be left
 * alone on the assumption that the caller knows best.
 *
 * because MPI-IO hints are optional, we can get away with limited error
 * reporting.
 *
 * for better scalability, the config file will be read on one processor and
 * broadcast to all others */
static int file_to_info_all(int fd, MPI_Info info, int rank, MPI_Comm comm)
{
    char *buffer, *token, *key, *val, *garbage;
    char *pos1 = NULL, *pos2 = NULL;
    int flag;
    ssize_t ret;
    int valuelen;

    /* assumption: config files will be small */
#define HINTFILE_MAX_SIZE 1024*4
    buffer = (char *) ADIOI_Calloc(HINTFILE_MAX_SIZE, sizeof(char));

    if (rank == 0) {
        ret = (fd >= 0) ? read(fd, buffer, HINTFILE_MAX_SIZE) : -1;
        /* any error: bad/nonexistent fd, no perms, anything: set up a null
         * buffer and the subsequent string parsing will quit immediately */
        if (ret == -1)
            buffer[0] = '\0';
    }
    MPI_Bcast(buffer, HINTFILE_MAX_SIZE, MPI_BYTE, 0, comm);

    token = strtok_r(buffer, "\n", &pos1);
    if (token == NULL)
        goto fn_exit;
    do {
        if ((key = strtok_r(token, " \t", &pos2)) == NULL)
            /* malformed line: found no items */
            continue;
        if (token[0] == '#')
            /* ignore '#'-delimited comments */
            continue;
        if ((val = strtok_r(NULL, " \t", &pos2)) == NULL)
            /* malformed line: found key without value */
            continue;
        if ((garbage = strtok_r(NULL, " \t", &pos2)) != NULL)
            /* malformed line: more than two items */
            continue;

#ifdef SYSHINT_DEBUG
        printf("found: key=%s val=%s\n", key, val);
#endif
        /* don't actually care what the value is. only want to know if key
         * exists: we leave it alone if so*/
        ADIOI_Info_get_valuelen(info, key, &valuelen, &flag);
        if (flag == 1)
            continue;
        ADIOI_Info_set(info, key, val);
    } while ((token = strtok_r(NULL, "\n", &pos1)) != NULL);

  fn_exit:
    ADIOI_Free(buffer);
    return 0;
}

void ADIOI_process_system_hints(ADIO_File fd, MPI_Info info)
{
    int hintfd = -1, rank;

    MPI_Comm_rank(fd->comm, &rank);
    if (rank == 0) {
        hintfd = find_file();
    }
    /* hintfd only significant on rank 0.  -1 (on rank 0) means no hintfile found  */
    file_to_info_all(hintfd, info, rank, fd->comm);

    if (hintfd != -1)
        close(hintfd);
}

/* given 'info', incorporate any hints in 'sysinfo' that are not already set
 * into 'new_info'.  Caller must free 'new_info' later. */
void ADIOI_incorporate_system_hints(MPI_Info info, MPI_Info sysinfo, MPI_Info * new_info)
{
    int i, nkeys_sysinfo, nkeys_info = 0, flag = 0;     /* must initialize flag to 0 */
    int valuelen;

    char val[MPI_MAX_INFO_VAL + 1], key[MPI_MAX_INFO_KEY + 1];

    if (sysinfo == MPI_INFO_NULL)
        nkeys_sysinfo = 0;
    else
        MPI_Info_get_nkeys(sysinfo, &nkeys_sysinfo);

    /* short-circuit: return immediately if no hints to process */
    if (info == MPI_INFO_NULL && nkeys_sysinfo == 0) {
        *new_info = MPI_INFO_NULL;
        return;
    }

    if (info == MPI_INFO_NULL)
        MPI_Info_create(new_info);
    else {
        /* tiny optimization: if 'info' has no keys, we can skip the check if a
         * hint is set: no keys means nothing has been set, and there's nothing
         * we might step on */
        MPI_Info_get_nkeys(info, &nkeys_info);
        MPI_Info_dup(info, new_info);
    }

    for (i = 0; i < nkeys_sysinfo; i++) {
        MPI_Info_get_nthkey(sysinfo, i, key);
        /* don't care about the value, just want to know if hint set already */
        if (info != MPI_INFO_NULL && nkeys_info)
            ADIOI_Info_get_valuelen(info, key, &valuelen, &flag);
        if (flag == 1)
            continue;   /* skip any hints already set by user */
        ADIOI_Info_get(sysinfo, key, MPI_MAX_INFO_VAL, val, &flag);
        ADIOI_Info_set(*new_info, key, val);
        flag = 0;
    }

    return;
}