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;
}
|