@@ -76,21 +76,86 @@ void check_connector_env(e3sm_io_config *cfg) {
7676 free (env_str );
7777}
7878
79- static inline int set_info (e3sm_io_config * cfg , e3sm_io_decom * decom ) {
79+ static
80+ int parse_hint_line (e3sm_io_config * cfg ,
81+ char * hint_str )
82+ {
83+ char * warn_str = "Warning: skip ill-formed hint set in PNETCDF_HINTS" ;
84+ char * next_hint , * key , * val , * deli ;
85+ int err = MPI_SUCCESS ;
86+
87+ if (hint_str == NULL ) return 1 ;
88+
89+ /* skip blank lines */
90+ char * hint_saved = strdup (hint_str );
91+ if (strlen (hint_str ) == 0 || strtok (hint_saved , " \t" ) == NULL ) {
92+ free (hint_saved );
93+ return 1 ;
94+ }
95+
96+ next_hint = hint_str ;
97+ do {
98+ hint_str = next_hint ;
99+ deli = strchr (hint_str , ';' );
100+ if (deli != NULL ) {
101+ * deli = '\0' ; /* add terminate char */
102+ next_hint = deli + 1 ;
103+ }
104+ else break ; /* done with this line */
105+
106+ deli = strchr (hint_str , '=' );
107+ if (deli == NULL ) { /* ill-formed hint */
108+ printf ("%s: '%s'\n" , warn_str , hint_str );
109+ continue ;
110+ }
111+ * deli = '\0' ;
112+
113+ /* hint key */
114+ key = strtok (hint_str , "= \t" );
115+ if (key == NULL || NULL != strtok (NULL , "= \t" )) {
116+ /* expect one token before = */
117+ printf ("%s: '%s'\n" , warn_str , hint_str );
118+ continue ;
119+ }
120+
121+ /* hint value */
122+ val = strtok (deli + 1 , "= \t" );
123+ if (NULL != strtok (NULL , "= \t" )) {
124+ /* expect one token before = */
125+ printf ("%s: '%s'\n" , warn_str , hint_str );
126+ continue ;
127+ }
128+
129+ /* override previouse set hint or add a new one */
130+ err = MPI_Info_set (cfg -> info , key , val );
131+ CHECK_MPIERR
132+
133+ } while (* next_hint != '\0' );
134+
135+ err_out :
136+ return err ;
137+ }
138+
139+ static inline int set_info (e3sm_io_config * cfg ,
140+ char * hint_str )
141+ {
80142 int err ;
81143
82144 /* set MPI-IO hints */
83145
146+ err = MPI_Info_create (& (cfg -> info ));
147+ CHECK_MPIERR
148+
84149 /* collective write */
85150 err = MPI_Info_set (cfg -> info , "romio_cb_write" , "enable" );
86151 CHECK_MPIERR
87152
88153 /* HDF5 may do independent I/O internally */
89154
90155 if (cfg -> api == pnetcdf ) {
91- /* no independent MPI-IO */
92- err = MPI_Info_set (cfg -> info , "romio_no_indep_rw" , "true" );
93- CHECK_MPIERR
156+ /* set MPI-IO hints here */
157+ // err = MPI_Info_set (cfg->info, "romio_no_indep_rw", "true");
158+ // CHECK_MPIERR
94159
95160 /* set PnetCDF I/O hints */
96161
@@ -121,6 +186,9 @@ static inline int set_info (e3sm_io_config *cfg, e3sm_io_decom *decom) {
121186 /* in-place byte swap */
122187 err = MPI_Info_set (cfg -> info , "nc_in_place_swap" , "enable" );
123188 CHECK_MPIERR
189+
190+ err = parse_hint_line (cfg , hint_str );
191+ if (err == 0 ) goto err_out ;
124192 }
125193
126194err_out :
@@ -224,7 +292,7 @@ int main (int argc, char **argv) {
224292 CHECK_ERR ;
225293#endif
226294
227- timing [0 ] = MPI_Wtime ();
295+ timing [1 ] = MPI_Wtime ();
228296
229297 MPI_Comm_rank (MPI_COMM_WORLD , & (cfg .rank ));
230298 MPI_Comm_size (MPI_COMM_WORLD , & (cfg .np ));
@@ -562,7 +630,7 @@ int main (int argc, char **argv) {
562630 PRINT_MSG (1 , "Input data file/folder name = %s\n" , cfg .in_path );
563631 PRINT_MSG (1 , "Output data file/folder name = %s\n" , cfg .out_path );
564632
565- timing [1 ] = MPI_Wtime () - timing [0 ];
633+ timing [1 ] = MPI_Wtime () - timing [1 ];
566634 MPI_Barrier (MPI_COMM_WORLD );
567635 timing [2 ] = MPI_Wtime ();
568636
@@ -584,41 +652,68 @@ int main (int argc, char **argv) {
584652 cfg .run_case = unknown ;
585653
586654 timing [2 ] = MPI_Wtime () - timing [2 ];
587- MPI_Barrier (MPI_COMM_WORLD );
588- timing [3 ] = MPI_Wtime ();
589655
590- /* set MPI-IO and PnetCDF hints */
591- err = MPI_Info_create (& (cfg .info ));
592- CHECK_MPIERR
593- err = set_info (& cfg , & decom );
594- if (err < 0 ) goto err_out ;
656+ /* read I/O hints from file e3sm_io_hints.txt, run e3sm_io_core() one per
657+ * line in the hint file. Each line contains hints as if it is set in the
658+ * environment variable PNETCDF_HINTS.
659+ */
660+ FILE * fptr = fopen ("e3sm_io_hints.txt" , "r" );
661+ char hint_str [512 ];
662+ int next_line ;
663+ if (fptr == NULL ) /* ignore hint file if not exist */
664+ next_line = EOF ;
665+ else /* get the first line of the hint file */
666+ next_line = fscanf (fptr , "%s" , hint_str );
595667
596- /* the core of this benchmark */
597- err = e3sm_io_core (& cfg , & decom );
598- CHECK_ERR
668+ do {
599669
600- timing [3 ] = MPI_Wtime () - timing [3 ];
601- MPI_Barrier (MPI_COMM_WORLD );
602- timing [4 ] = MPI_Wtime ();
670+ if (cfg .rank == 0 ) printf ("\nHINTS: %s\n\n" , (next_line == EOF ) ? "" : hint_str );
603671
604- /* report timing breakdowns */
605- if (cfg .rd ) {
606- report_timing_RD (& cfg , & decom );
607- }
608- else {
609- report_timing_WR (& cfg , & decom );
610- }
672+ /* the core of this benchmark */
673+ MPI_Barrier (MPI_COMM_WORLD );
674+ timing [3 ] = MPI_Wtime ();
675+
676+ /* set MPI-IO and PnetCDF hints */
677+ err = set_info (& cfg , (next_line == EOF ) ? NULL : hint_str );
678+ if (err < 0 ) goto err_out ;
679+
680+ err = e3sm_io_core (& cfg , & decom );
681+ CHECK_ERR
682+
683+ timing [3 ] = MPI_Wtime () - timing [3 ];
684+
685+ /* report timing breakdowns */
686+ if (cfg .rd )
687+ report_timing_RD (& cfg , & decom );
688+ else
689+ report_timing_WR (& cfg , & decom );
611690
612691#ifdef E3SM_IO_PROFILING
613- if (cfg .profiling ) e3sm_io_print_profile (& cfg );
692+ if (cfg .profiling ) e3sm_io_print_profile (& cfg );
614693#else
615- if (cfg .profiling && cfg .rank == 0 )
616- printf ("\nWarning: E3SM-IO internal time profiling was disabled at configure time\n\n" );
694+ if (cfg .profiling && cfg .rank == 0 )
695+ printf ("\nWarning: E3SM-IO internal time profiling was disabled at configure time\n\n" );
617696#endif
618697
698+ if (cfg .info != MPI_INFO_NULL ) MPI_Info_free (& (cfg .info ));
699+
700+ timing [0 ] = timing [1 ] + timing [2 ] + timing [3 ];
701+ MPI_Reduce (timing , max_t , 4 , MPI_DOUBLE , MPI_MAX , 0 , MPI_COMM_WORLD );
702+ if (cfg .rank == 0 ) {
703+ printf ("init=%.2f read_decomp=%.2f e3sm_io_core=%.2f end-to-end=%.2f\n" ,
704+ max_t [1 ],max_t [2 ],max_t [3 ],max_t [0 ]);
705+ printf ("-----------------------------------------------------------\n" );
706+ printf ("\n\n" );
707+ }
708+
709+ if (fptr == NULL ) break ;
710+
711+ next_line = fscanf (fptr , "%s" , hint_str );
712+ } while (next_line != EOF );
713+
714+ if (fptr != NULL ) fclose (fptr );
715+
619716err_out :
620- if (cfg .info != MPI_INFO_NULL )
621- MPI_Info_free (& (cfg .info ));
622717 if (cfg .io_comm != MPI_COMM_WORLD && cfg .io_comm != MPI_COMM_NULL )
623718 MPI_Comm_free (& (cfg .io_comm ));
624719 if (cfg .env_log_info != NULL )
@@ -635,16 +730,6 @@ int main (int argc, char **argv) {
635730 }
636731 }
637732
638- timing [4 ] = MPI_Wtime () - timing [4 ];
639- timing [0 ] = MPI_Wtime () - timing [0 ];
640- MPI_Reduce (timing , max_t , 5 , MPI_DOUBLE , MPI_MAX , 0 , MPI_COMM_WORLD );
641- if (cfg .rank == 0 ) {
642- printf ("init=%.2f read_decomp=%.2f e3sm_io_core=%.2f final=%.2f end-to-end=%.2f\n" ,
643- max_t [1 ],max_t [2 ],max_t [3 ],max_t [4 ],max_t [0 ]);
644- printf ("-----------------------------------------------------------\n" );
645- printf ("\n\n" );
646- }
647-
648733 MPI_Finalize ();
649734
650735 return (err < 0 ) ? 1 : 0 ;
0 commit comments