@@ -76,21 +76,88 @@ 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+ deli = strchr (hint_str , ';' );
99+ if (deli != NULL ) {
100+ * deli = '\0' ; /* add terminate char */
101+ next_hint = deli + 1 ;
102+ }
103+ else break ; /* done with this line */
104+
105+ /* skip all-blank hint, i.e. blanks in between 2 ';' */
106+ if (strtok (NULL , " \t" ) == NULL ) continue ;
107+
108+ deli = strchr (hint_str , '=' );
109+ if (deli == NULL ) { /* ill-formed hint */
110+ printf ("%s: '%s'\n" , warn_str , hint_str );
111+ continue ;
112+ }
113+ * deli = '\0' ;
114+
115+ /* hint key */
116+ key = strtok (NULL , "= \t" );
117+ if (key == NULL || NULL != strtok (NULL , "= \t" )) {
118+ /* expect one token before = */
119+ printf ("%s: '%s'\n" , warn_str , hint_str );
120+ continue ;
121+ }
122+
123+ /* hint value */
124+ val = strtok (deli + 1 , "= \t" );
125+ if (NULL != strtok (NULL , "= \t" )) {
126+ /* expect one token before = */
127+ printf ("%s: '%s'\n" , warn_str , hint_str );
128+ continue ;
129+ }
130+
131+ /* override previouse set hint or add a new one */
132+ err = MPI_Info_set (cfg -> info , key , val );
133+ CHECK_MPIERR
134+
135+ } while (* next_hint != '\0' );
136+
137+ err_out :
138+ return err ;
139+ }
140+
141+ static inline int set_info (e3sm_io_config * cfg ,
142+ char * hint_str )
143+ {
80144 int err ;
81145
82146 /* set MPI-IO hints */
83147
148+ err = MPI_Info_create (& (cfg -> info ));
149+ CHECK_MPIERR
150+
84151 /* collective write */
85152 err = MPI_Info_set (cfg -> info , "romio_cb_write" , "enable" );
86153 CHECK_MPIERR
87154
88155 /* HDF5 may do independent I/O internally */
89156
90157 if (cfg -> api == pnetcdf ) {
91- /* no independent MPI-IO */
92- err = MPI_Info_set (cfg -> info , "romio_no_indep_rw" , "true" );
93- CHECK_MPIERR
158+ /* set MPI-IO hints here */
159+ // err = MPI_Info_set (cfg->info, "romio_no_indep_rw", "true");
160+ // CHECK_MPIERR
94161
95162 /* set PnetCDF I/O hints */
96163
@@ -121,6 +188,9 @@ static inline int set_info (e3sm_io_config *cfg, e3sm_io_decom *decom) {
121188 /* in-place byte swap */
122189 err = MPI_Info_set (cfg -> info , "nc_in_place_swap" , "enable" );
123190 CHECK_MPIERR
191+
192+ err = parse_hint_line (cfg , hint_str );
193+ if (err == 0 ) goto err_out ;
124194 }
125195
126196err_out :
@@ -224,7 +294,7 @@ int main (int argc, char **argv) {
224294 CHECK_ERR ;
225295#endif
226296
227- timing [0 ] = MPI_Wtime ();
297+ timing [1 ] = MPI_Wtime ();
228298
229299 MPI_Comm_rank (MPI_COMM_WORLD , & (cfg .rank ));
230300 MPI_Comm_size (MPI_COMM_WORLD , & (cfg .np ));
@@ -562,7 +632,7 @@ int main (int argc, char **argv) {
562632 PRINT_MSG (1 , "Input data file/folder name = %s\n" , cfg .in_path );
563633 PRINT_MSG (1 , "Output data file/folder name = %s\n" , cfg .out_path );
564634
565- timing [1 ] = MPI_Wtime () - timing [0 ];
635+ timing [1 ] = MPI_Wtime () - timing [1 ];
566636 MPI_Barrier (MPI_COMM_WORLD );
567637 timing [2 ] = MPI_Wtime ();
568638
@@ -584,41 +654,68 @@ int main (int argc, char **argv) {
584654 cfg .run_case = unknown ;
585655
586656 timing [2 ] = MPI_Wtime () - timing [2 ];
587- MPI_Barrier (MPI_COMM_WORLD );
588- timing [3 ] = MPI_Wtime ();
589657
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 ;
658+ /* read I/O hints from file e3sm_io_hints.txt, run e3sm_io_core() one per
659+ * line in the hint file. Each line contains hints as if it is set in the
660+ * environment variable PNETCDF_HINTS.
661+ */
662+ FILE * fptr = fopen ("e3sm_io_hints.txt" , "r" );
663+ char hint_str [512 ];
664+ int next_line ;
665+ if (fptr == NULL ) /* ignore hint file if not exist */
666+ next_line = EOF ;
667+ else /* get the first line of the hint file */
668+ next_line = fscanf (fptr , "%s" , hint_str );
595669
596- /* the core of this benchmark */
597- err = e3sm_io_core (& cfg , & decom );
598- CHECK_ERR
670+ do {
599671
600- timing [3 ] = MPI_Wtime () - timing [3 ];
601- MPI_Barrier (MPI_COMM_WORLD );
602- timing [4 ] = MPI_Wtime ();
672+ if (cfg .rank == 0 ) printf ("\nHINTS: %s\n\n" , (next_line == EOF ) ? "" : hint_str );
603673
604- /* report timing breakdowns */
605- if (cfg .rd ) {
606- report_timing_RD (& cfg , & decom );
607- }
608- else {
609- report_timing_WR (& cfg , & decom );
610- }
674+ /* the core of this benchmark */
675+ MPI_Barrier (MPI_COMM_WORLD );
676+ timing [3 ] = MPI_Wtime ();
677+
678+ /* set MPI-IO and PnetCDF hints */
679+ err = set_info (& cfg , (next_line == EOF ) ? NULL : hint_str );
680+ if (err < 0 ) goto err_out ;
681+
682+ err = e3sm_io_core (& cfg , & decom );
683+ CHECK_ERR
684+
685+ timing [3 ] = MPI_Wtime () - timing [3 ];
686+
687+ /* report timing breakdowns */
688+ if (cfg .rd )
689+ report_timing_RD (& cfg , & decom );
690+ else
691+ report_timing_WR (& cfg , & decom );
611692
612693#ifdef E3SM_IO_PROFILING
613- if (cfg .profiling ) e3sm_io_print_profile (& cfg );
694+ if (cfg .profiling ) e3sm_io_print_profile (& cfg );
614695#else
615- if (cfg .profiling && cfg .rank == 0 )
616- printf ("\nWarning: E3SM-IO internal time profiling was disabled at configure time\n\n" );
696+ if (cfg .profiling && cfg .rank == 0 )
697+ printf ("\nWarning: E3SM-IO internal time profiling was disabled at configure time\n\n" );
617698#endif
618699
700+ if (cfg .info != MPI_INFO_NULL ) MPI_Info_free (& (cfg .info ));
701+
702+ timing [0 ] = timing [1 ] + timing [2 ] + timing [3 ];
703+ MPI_Reduce (timing , max_t , 4 , MPI_DOUBLE , MPI_MAX , 0 , MPI_COMM_WORLD );
704+ if (cfg .rank == 0 ) {
705+ printf ("init=%.2f read_decomp=%.2f e3sm_io_core=%.2f end-to-end=%.2f\n" ,
706+ max_t [1 ],max_t [2 ],max_t [3 ],max_t [0 ]);
707+ printf ("-----------------------------------------------------------\n" );
708+ printf ("\n\n" );
709+ }
710+
711+ if (fptr == NULL ) break ;
712+
713+ next_line = fscanf (fptr , "%s" , hint_str );
714+ } while (next_line != EOF );
715+
716+ if (fptr != NULL ) fclose (fptr );
717+
619718err_out :
620- if (cfg .info != MPI_INFO_NULL )
621- MPI_Info_free (& (cfg .info ));
622719 if (cfg .io_comm != MPI_COMM_WORLD && cfg .io_comm != MPI_COMM_NULL )
623720 MPI_Comm_free (& (cfg .io_comm ));
624721 if (cfg .env_log_info != NULL )
@@ -635,16 +732,6 @@ int main (int argc, char **argv) {
635732 }
636733 }
637734
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-
648735 MPI_Finalize ();
649736
650737 return (err < 0 ) ? 1 : 0 ;
0 commit comments