1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*-
2 * vim: ts=8 sts=4 sw=4 noexpandtab
3 *
4 * Copyright (C) 2007 UChicago/Argonne LLC.
5 * See COPYRIGHT notice in top-level directory.
6 */
7
8 #include <adio.h>
9
10 #include <stdio.h>
11
12 #ifdef HAVE_FCNTL_H
13 #include <fcntl.h>
14 #endif
15 #ifdef HAVE_SYS_TYPES_H
16 #include <sys/types.h>
17 #endif
18 #include <stdlib.h>
19 #include <string.h>
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23 #ifdef HAVE_IO_H
24 #include <io.h>
25 #endif
26
27 /*#define SYSHINT_DEBUG 1 */
28
29 #define ROMIO_HINT_DEFAULT_CFG "/etc/romio-hints"
30 #define ROMIO_HINT_ENV_VAR "ROMIO_HINTS"
31
32 /* debug function: a routine I want in the library to make my life easier when
33 * using a source debugger. Now optionally used in ADIO_Open. */
ADIOI_Info_print_keyvals(MPI_Info info)34 void ADIOI_Info_print_keyvals(MPI_Info info)
35 {
36 int i, nkeys, flag;
37 char key[MPI_MAX_INFO_KEY];
38 char value[MPI_MAX_INFO_VAL];
39
40 if (info == MPI_INFO_NULL)
41 return;
42
43 MPI_Info_get_nkeys(info, &nkeys);
44
45 for (i=0; i<nkeys; i++) {
46 MPI_Info_get_nthkey(info, i, key);
47 ADIOI_Info_get(info, key, MPI_MAX_INFO_VAL-1, value, &flag);
48 printf("key = %-25s value = %-10s\n", key, value);
49 }
50 return;
51 }
52
53 /* if user set the environment variable, use its value to find the
54 * file-of-hints. Otherwise, we'll look for the default config file. i.e. let
55 * the user override systemwide hint processing */
56
find_file(void)57 static int find_file(void)
58 {
59 int fd=-1;
60 char * hintfile;
61
62 hintfile = getenv(ROMIO_HINT_ENV_VAR);
63 if(hintfile)
64 fd = open(hintfile, O_RDONLY);
65 if (fd < 0 )
66 fd = open(ROMIO_HINT_DEFAULT_CFG, O_RDONLY);
67
68 return fd;
69 }
70
71 /* parse the file-of-hints. Format is zero or more lines of "<key> <value>\n".
72 * A # in collumn zero is a comment and the line will be ignored. Do our best
73 * to ignore badly formed lines too.
74 *
75 * The caller provides an 'info' object. Each key-value pair found by the
76 * parser will get added to the info object. any keys already set will be left
77 * alone on the assumption that the caller knows best.
78 *
79 * because MPI-IO hints are optional, we can get away with limited error
80 * reporting.
81 *
82 * for better scalability, the config file will be read on one processor and
83 * broadcast to all others */
file_to_info_all(int fd,MPI_Info info,int rank,MPI_Comm comm)84 static int file_to_info_all(int fd, MPI_Info info, int rank, MPI_Comm comm)
85 {
86 char *buffer, *token, *key, *val, *garbage;
87 char *pos1=NULL, *pos2=NULL;
88 int flag;
89 ssize_t ret;
90 char dummy;
91
92 /* assumption: config files will be small */
93 #define HINTFILE_MAX_SIZE 1024*4
94 buffer = (char *)ADIOI_Calloc(HINTFILE_MAX_SIZE, sizeof (char));
95
96 if (rank == 0) {
97 ret = read(fd, buffer, HINTFILE_MAX_SIZE);
98 /* any error: bad/nonexistent fd, no perms, anything: set up a null
99 * buffer and the subsequent string parsing will quit immediately */
100 if (ret == -1)
101 buffer[0] = '\0';
102 }
103 MPI_Bcast(buffer, HINTFILE_MAX_SIZE, MPI_BYTE, 0, comm);
104
105 token = strtok_r(buffer, "\n", &pos1);
106 if (token == NULL)
107 goto fn_exit;
108 do {
109 if ( (key = strtok_r(token, " \t", &pos2)) == NULL)
110 /* malformed line: found no items */
111 continue;
112 if (token[0] == '#')
113 /* ignore '#'-delimited comments */
114 continue;
115 if ( (val = strtok_r(NULL, " \t", &pos2)) == NULL)
116 /* malformed line: found key without value */
117 continue;
118 if ( (garbage = strtok_r(NULL, " \t", &pos2)) != NULL)
119 /* malformed line: more than two items */
120 continue;
121
122 #ifdef SYSHINT_DEBUG
123 printf("found: key=%s val=%s\n", key, val);
124 #endif
125 /* don't actually care what the value is. only want to know if key
126 * exists: we leave it alone if so*/
127 ADIOI_Info_get(info, key, 1, &dummy, &flag);
128 if (flag == 1) continue;
129 ADIOI_Info_set(info, key, val);
130 } while ((token = strtok_r(NULL, "\n", &pos1)) != NULL);
131
132 fn_exit:
133 ADIOI_Free(buffer);
134 return 0;
135 }
136
ADIOI_process_system_hints(ADIO_File fd,MPI_Info info)137 void ADIOI_process_system_hints(ADIO_File fd, MPI_Info info)
138 {
139 int hintfd=-1, rank;
140
141 MPI_Comm_rank(fd->comm, &rank);
142 if (rank == 0) {
143 hintfd = find_file();
144 }
145 /* hintfd only significant on rank 0. -1 (on rank 0) means no hintfile found */
146 file_to_info_all(hintfd, info, rank, fd->comm);
147
148 if (hintfd != -1)
149 close(hintfd);
150 }
151
152 /* given 'info', incorporate any hints in 'sysinfo' that are not already set
153 * into 'new_info'. Caller must free 'new_info' later. */
ADIOI_incorporate_system_hints(MPI_Info info,MPI_Info sysinfo,MPI_Info * new_info)154 void ADIOI_incorporate_system_hints(MPI_Info info,
155 MPI_Info sysinfo,
156 MPI_Info *new_info)
157 {
158 int i, nkeys_sysinfo, flag=0; /* must initialize flag to 0 */
159
160 char val[MPI_MAX_INFO_VAL], key[MPI_MAX_INFO_KEY];
161
162 if (sysinfo == MPI_INFO_NULL)
163 nkeys_sysinfo = 0;
164 else
165 MPI_Info_get_nkeys(sysinfo, &nkeys_sysinfo);
166
167 /* short-circuit: return immediately if no hints to process */
168 if (info == MPI_INFO_NULL && nkeys_sysinfo == 0) {
169 *new_info = MPI_INFO_NULL;
170 return;
171 }
172
173 if (info == MPI_INFO_NULL)
174 MPI_Info_create(new_info);
175 else
176 MPI_Info_dup(info, new_info);
177
178 for (i=0; i<nkeys_sysinfo; i++) {
179 MPI_Info_get_nthkey(sysinfo, i, key);
180 /* don't care about the value, just want to know if hint set already*/
181 if (info != MPI_INFO_NULL) ADIOI_Info_get(info, key, 1, val, &flag);
182 if (flag == 1) continue; /* skip any hints already set by user */
183 ADIOI_Info_get(sysinfo, key, MPI_MAX_INFO_VAL-1, val, &flag);
184 ADIOI_Info_set(*new_info, key, val);
185 flag = 0;
186 }
187
188 return;
189 }
190
191
192