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