ZC Bcast Post API: Add guard for resetting envelope type and ep
[charm.git] / smart-build.pl
1 #!/usr/bin/env perl
2
3
4 # This is an interactive script that knows
5 # common ways to build Charm++ and AMPI.
6 #
7 # Authors: dooley, becker
8
9 use strict;
10 use warnings;
11
12 # Get location of script
13 use File::Basename;
14 my $dirname = dirname(__FILE__);
15
16 # Create temporary file for compiler tests
17 use File::Temp qw(tempfile);
18 my $tempfile = new File::Temp(UNLINK => 1, SUFFIX => '.c');
19 print $tempfile "\n";
20
21 # Turn off I/O buffering
22 $| = 1;
23
24
25
26 # A subroutine that reads from input and returns a yes/no/default
27 sub promptUserYN {
28   while(my $line = <>){
29         chomp $line;
30         if(lc($line) eq "y" || lc($line) eq "yes" ){
31           return "yes";
32         } elsif(lc($line) eq "n" || lc($line) eq "no" ){
33           return "no";
34         } elsif( $line eq "" ){
35           return "default";
36         }
37   }
38 }
39
40
41 # The beginning of the good stuff:
42 print "\n============================================================\n";
43 print "\nInteractive Charm++/AMPI configuration ...\n";
44 print "If you are a power user expecting a list of options, please use ./build --help\n";
45 print "\n============================================================\n\n\n";
46
47
48 # Use uname to get the cpu type and OS information
49 my $os = `uname -s`;
50 my $cpu = `uname -m`;
51
52 #Variables to hold the portions of the configuration:
53 my $nobs = "";
54 my $arch = "";
55 my $compilers = "";
56 my $options = "";
57
58 #remove newlines from these strings:
59 chomp($os);
60 chomp ($cpu);
61
62 my $arch_os;
63 # Determine OS kernel
64 if ($os eq "Linux") {
65   $arch_os = "linux";
66 } elsif ($os eq "Darwin") {
67   $arch_os = "darwin";
68 } elsif ($os =~ m/BSD/ ) {
69   $arch_os = "linux";
70 } elsif ($os =~ m/OSF1/ ) {
71   $arch_os = "linux";
72 }
73
74
75 my $x86;
76 my $amd64;
77 my $ppc;
78 my $arm7;
79 # Determine architecture (x86, ppc, ...)
80 if($cpu =~ m/i[0-9]86/){
81   $x86 = 1;
82 } elsif($cpu =~ m/x86\_64/){
83   $amd64 = 1;
84 } elsif($cpu =~ m/powerpc/){
85   $ppc = 1;
86 } elsif($cpu =~ m/ppc*/){
87   $ppc = 1;
88 } elsif($cpu =~ m/arm7/){
89   $arm7 = 1;
90 }
91
92
93 # default to netlrts
94 my $converse_network_type = "netlrts";
95 my $skip_choosing = "false";
96
97 print "Are you building to run just on the local machine, and not across multiple nodes? [";
98 if($arch_os eq "darwin") {
99     print "Y/n]: ";
100 } else {
101     print "y/N]: ";
102 }
103 {
104     my $p = promptUserYN();
105     if($p eq "yes" || ($arch_os eq "darwin" && $p eq "default")){
106         $converse_network_type = "multicore";
107         $skip_choosing = "true";
108     }
109 }
110
111
112 # check for BG/Q
113
114 if($skip_choosing eq "false"){
115   my $BGQ_FLOOR = $ENV{'BGQ_FLOOR'};
116   if (not defined $BGQ_FLOOR) {
117     $BGQ_FLOOR = "/bgsys/drivers/ppcfloor";
118   }
119
120   my $bgq_found = system("which \"$BGQ_FLOOR/gnu-linux/bin/powerpc64-bgq-linux-cpp\" 2>/dev/null") / 256;
121
122   if ($bgq_found == 0) {
123     print "\nI found that you have a Blue Gene/Q toolchain available in your path.\nDo you want to build Charm++ targeting BG/Q? [Y/n]: ";
124     my $p = promptUserYN();
125     if($p eq "yes" || $p eq "default") {
126       $arch = "pamilrts-bluegeneq";
127       $skip_choosing = "true";
128     }
129   }
130 }
131
132
133 # check for GNI
134
135 if($skip_choosing eq "false"){
136   my $craycc_found = index(`which CC 2>/dev/null`, "/opt/cray/") != -1;
137
138   my $PE_PRODUCT_LIST = $ENV{'PE_PRODUCT_LIST'};
139   if (not defined $PE_PRODUCT_LIST) {
140     $PE_PRODUCT_LIST = "";
141   }
142
143   my $CRAY_UGNI_found = index(":$PE_PRODUCT_LIST:", ":CRAY_UGNI:") != -1;
144
145   my $gni_found = $craycc_found || $CRAY_UGNI_found;
146
147   if ($gni_found) {
148     my $CRAYPE_INTERLAGOS_found = index(":$PE_PRODUCT_LIST:", ":CRAYPE_INTERLAGOS:") != -1;
149     if ($CRAYPE_INTERLAGOS_found) {
150       print "\nI found that you have a Cray environment with Interlagos processors.\nDo you want to build Charm++ targeting Cray XE? [Y/n]: ";
151       my $p = promptUserYN();
152       if($p eq "yes" || $p eq "default") {
153                     $arch = "gni-crayxe";
154                     $skip_choosing = "true";
155       }
156     } else {
157       print "\nI found that you have a Cray environment.\nDo you want to build Charm++ targeting Cray XC? [Y/n]: ";
158       my $p = promptUserYN();
159       if($p eq "yes" || $p eq "default") {
160                     $arch = "gni-crayxc";
161                     $skip_choosing = "true";
162       }
163     }
164   }
165 }
166
167
168 # check for OFI
169
170 if($skip_choosing eq "false"){
171   my $ofi_found = index(`cc $tempfile -Wl,-lfabric 2>&1`, "-lfabric") == -1;
172
173   if ($ofi_found) {
174     print "\nI found that you have libfabric available in your toolchain.\nDo you want to build Charm++ targeting OFI? [Y/n]: ";
175     my $p = promptUserYN();
176     if($p eq "yes" || $p eq "default") {
177       $converse_network_type = "ofi";
178       $skip_choosing = "true";
179     }
180   }
181 }
182
183
184 # check for PAMI
185
186 if($skip_choosing eq "false"){
187   my $MPI_ROOT = $ENV{'MPI_ROOT'};
188   if (not defined $MPI_ROOT) {
189     $MPI_ROOT = "";
190   }
191
192   my $pami_found = index(`cc $tempfile -Wl,-L,"$MPI_ROOT/lib/pami_port" -Wl,-L,/usr/lib/powerpc64le-linux-gnu -Wl,-lpami 2>&1`, "-lpami") == -1;
193
194   if ($pami_found) {
195     print "\nI found that you have libpami available in your toolchain.\nDo you want to build Charm++ targeting PAMI? [Y/n]: ";
196     my $p = promptUserYN();
197     if($p eq "yes" || $p eq "default") {
198       $converse_network_type = "pamilrts";
199       $skip_choosing = "true";
200     }
201   }
202 }
203
204
205 # check for Verbs
206
207 if($skip_choosing eq "false"){
208   my $verbs_found = index(`cc $tempfile -Wl,-libverbs 2>&1`, "-libverbs") == -1;
209
210   if ($verbs_found) {
211     print "\nI found that you have libibverbs available in your toolchain.\nDo you want to build Charm++ targeting Infiniband Verbs? [Y/n]: ";
212     my $p = promptUserYN();
213     if($p eq "yes" || $p eq "default") {
214       $converse_network_type = "verbs";
215       $skip_choosing = "true";
216     }
217   }
218 }
219
220
221 # check for MPI
222
223 if($skip_choosing eq "false"){
224   my $mpi_found = "false";
225   my $m = system("which mpicc mpiCC > /dev/null 2>/dev/null") / 256;
226   my $mpioption;
227   if($m == 0){
228       $mpi_found = "true";
229       $mpioption = "";
230   }
231   $m = system("which mpicc mpicxx > /dev/null 2>/dev/null") / 256;
232   if($m == 0){
233       $mpi_found = "true";
234       $mpioption = "mpicxx";
235   }
236
237   # Give option of just using the mpi version if mpicc and mpiCC are found
238   if($mpi_found eq "true"){
239     print "\nI found that you have an mpicc available in your path.\nDo you want to build Charm++ on this MPI? [y/N]: ";
240     my $p = promptUserYN();
241     if($p eq "yes"){
242     $converse_network_type = "mpi";
243     $skip_choosing = "true";
244     $options = "$options $mpioption";
245     }
246   }
247 }
248
249
250 if($skip_choosing eq "false") {
251
252   print "\nDo you have a special network interconnect? [y/N]: ";
253   my $p = promptUserYN();
254   if($p eq "yes"){
255
256         print << "EOF";
257
258 Choose an interconnect from below: [1-10]
259          1) MPI
260          2) Infiniband (verbs)
261          3) Cray XE, XK
262          4) Cray XC
263          5) Blue Gene/Q
264          6) Intel Omni-Path (ofi)
265          7) PAMI
266
267 EOF
268
269         while(my $line = <>){
270           chomp $line;
271           if($line eq "1"){
272                 $converse_network_type = "mpi";
273                 last;
274           } elsif($line eq "2"){
275                 $converse_network_type = "verbs";
276                 last;
277           } elsif($line eq "3"){
278                 $arch = "gni-crayxe";
279                 last;
280           } elsif($line eq "4"){
281                 $arch = "gni-crayxc";
282                 last;
283           } elsif($line eq "5"){
284                 $arch = "pamilrts-bluegeneq";
285                 last;
286           } elsif($line eq "6"){
287                 $converse_network_type = "ofi";
288                 last;
289           } elsif($line eq "7"){
290                 $converse_network_type = "pamilrts";
291                 last;
292           } else {
293                 print "Invalid option, please try again :P\n"
294           }
295         }
296   }
297 }
298
299
300 # check for CUDA
301
302 my $nvcc_found = "false";
303 my $n = system("which nvcc > /dev/null 2>/dev/null") / 256;
304 if($n == 0){
305   $nvcc_found = "true";
306 }
307
308 if($nvcc_found eq "true"){
309   print "\nI found that you have NVCC available in your path.\nDo you want to build Charm++ with GPU Manager support for CUDA? [y/N]: ";
310   my $p = promptUserYN();
311   if($p eq "yes") {
312     $options = "$options cuda";
313   }
314 }
315
316
317 # construct an $arch string if we did not explicitly set one above
318 if($arch eq ""){
319   $arch = "${converse_network_type}-${arch_os}";
320           if($amd64) {
321                 $arch = $arch . "-x86_64";
322           } elsif($ppc){
323                 $arch = $arch . "-ppc64le";
324           } elsif($arm7){
325                 $arch = $arch . "-arm7";
326           }
327 }
328
329 # Fixup $arch to match the inconsistent directories in src/archs
330
331 if($arch eq "netlrts-darwin"){
332         $arch = "netlrts-darwin-x86_64";
333 } elsif($arch eq "multicore-linux-arm7"){
334         $arch = "multicore-arm7";
335 }
336
337
338 #================ Choose SMP/PXSHM =================================
339
340 # find what options are available
341 my $opts = `$dirname/build charm++ $arch help 2>&1 | grep "Supported options"`;
342 $opts =~ m/Supported options: (.*)/;
343 $opts = $1;
344
345 my $smp_opts = <<EOF;
346       1) single-threaded [default]
347 EOF
348
349 # only add the smp or pxshm options if they are available
350 my $counter = 1; # the last index used in the list
351
352 my $smpIndex = -1;
353 if($opts =~ m/smp/){
354   $counter ++;
355   $smp_opts = $smp_opts . "      $counter) SMP\n";
356   $smpIndex = $counter;
357 }
358
359 my $pxshmIndex = -1;
360 if($opts =~ m/pxshm/){
361   $counter ++;
362   $smp_opts = $smp_opts . "      $counter) POSIX Shared Memory\n";
363   $pxshmIndex = $counter;
364 }
365
366 if ($counter != 1) {
367     print "\nHow do you want to handle SMP/Multicore: [1-$counter]\n";
368     print $smp_opts;
369
370     while(my $line = <>){
371         chomp $line;
372         if($line eq "" || $line eq "1"){
373             last;
374         } elsif($line eq $smpIndex){
375             $options = "$options smp ";
376             last;
377         } elsif($line eq $pxshmIndex){
378             $options = "$options pxshm ";
379             last;
380         }
381     }
382 }
383
384
385 #================ Choose Compiler =================================
386
387 # Lookup list of compilers
388 my $cs = `$dirname/build charm++ $arch help 2>&1 | grep "Supported compilers"`;
389 # prune away beginning of the line
390 $cs =~ m/Supported compilers: (.*)/;
391 $cs = $1;
392 # split the line into an array
393 my @c_list = split(" ", $cs);
394
395 # print list of compilers
396 my $numc = @c_list;
397
398 if ($numc > 0) {
399     print "\nDo you want to specify a compiler? [y/N]: ";
400     my $p = promptUserYN();
401     if($p eq "yes" ){
402         print "Choose a compiler: [1-$numc] \n";
403
404         my $i = 1;
405         foreach my $c (@c_list){
406             print "\t$i)\t$c\n";
407             $i++;
408         }
409
410         # Choose compiler
411         while(my $line = <>){
412             chomp $line;
413             if($line =~ m/([0-9]*)/ && $1 > 0 && $1 <= $numc){
414                 $compilers = $c_list[$1-1];
415                 last;
416             } else {
417                 print "Invalid option, please try again :P\n"
418             }
419         }
420     }
421 }
422
423
424
425
426 #================ Choose Options =================================
427
428 #Create a hash table containing descriptions of various options
429 my %explanations = ();
430 $explanations{"ooc"} = "Enable Out-of-core execution support in Charm++";
431 $explanations{"tcp"} = "Charm++ over TCP instead of UDP for net versions. TCP is slower";
432 $explanations{"gfortran"} = "Use the gfortran compiler for Fortran";
433 $explanations{"flang"} = "Use the flang compiler for Fortran";
434 $explanations{"ifort"} = "Use Intel's ifort Fortran compiler";
435 $explanations{"pgf90"} = "Use Portland Group's pgf90 Fortran compiler";
436 $explanations{"syncft"} = "Use fault tolerance support";
437 $explanations{"mlogft"} = "Use message logging fault tolerance support";
438 $explanations{"causalft"} = "Use causal message logging fault tolerance support";
439 $explanations{"omp"} = "Build Charm++ with integrated OpenMP support";
440 $explanations{"papi"} = "Enable PAPI performance counters";
441 $explanations{"pedantic"} = "Enable pedantic compiler warnings";
442 $explanations{"bigemulator"} = "Build additional BigSim libraries";
443 $explanations{"bigsim"} = "Compile Charm++ as running on the BigSim emulator";
444 $explanations{"nolb"} = "Build without load balancing support";
445 $explanations{"perftools"} = "Build with support for the Cray perftools";
446 $explanations{"persistent"} = "Build the persistent communication interface";
447 $explanations{"slurmpmi"} = "Use Slurm PMI for task launching";
448 $explanations{"slurmpmi2"} = "Use Slurm PMI2 for task launching";
449 $explanations{"tsan"} = "Compile Charm++ with support for Thread Sanitizer";
450
451
452
453
454
455   # Produce list of options
456
457   $opts = `$dirname/build charm++ $arch help 2>&1 | grep "Supported options"`;
458   # prune away beginning of line
459   $opts =~ m/Supported options: (.*)/;
460   $opts = $1;
461
462   my @option_list = split(" ", $opts);
463
464
465   # Prune out entries that would already have been chosen above, such as smp
466   my @option_list_pruned = ();
467   foreach my $o (@option_list){
468         if($o ne "smp" && $o ne "ibverbs" && $o ne "gm" && $o ne "mx"){
469           @option_list_pruned = (@option_list_pruned , $o);
470         }
471   }
472
473   # sort the list
474   @option_list_pruned = sort @option_list_pruned;
475   if (@option_list_pruned > 0) {
476
477       print "\nDo you want to specify any Charm++ build options, such as Fortran compilers? [y/N]: ";
478       my $special_options = promptUserYN();
479
480       if($special_options eq "yes"){
481
482           # print out list for user to select from
483           print "Please enter one or more numbers separated by spaces\n";
484           print "Choices:\n";
485           my $i = 1;
486           foreach my $o (@option_list_pruned){
487               my $exp = $explanations{$o};
488               print "\t$i)\t$o";
489               # pad whitespace before options
490               for(my $j=0;$j<20-length($o);$j++){
491                   print " ";
492               }
493               print "$exp";
494               print "\n";
495               $i++;
496           }
497           print "\t$i)\tNone Of The Above\n";
498
499           my $num_options = @option_list_pruned;
500
501           while(my $line = <>){
502               chomp $line;
503               $line =~ m/([0-9 ]*)/;
504               my @entries = split(" ",$1);
505               @entries = sort(@entries);
506
507               my $additional_options = "";
508               foreach my $e (@entries) {
509                   if($e>=1 && $e<= $num_options){
510                       my $estring = $option_list_pruned[$e-1];
511                       $additional_options = "$additional_options $estring";
512                   } elsif ($e == $num_options+1){
513                       # user chose "None of the above"
514                       # clear the options we may have seen before
515                       $additional_options = " ";
516                   }
517               }
518
519               # if the user input something reasonable, we can break out of this loop
520               if($additional_options ne ""){
521                   $options = "$options ${additional_options} ";
522                   last;
523               }
524
525           }
526       }
527   }
528
529
530 # Choose compiler flags
531 print << "EOF";
532
533 Choose a set of compiler flags [1-5]
534         1) none
535         2) debug mode                        -g -O0
536         3) production build [default]        --with-production
537         4) production build w/ projections   --with-production --enable-tracing
538         5) custom
539
540 EOF
541
542 my $compiler_flags = "";
543
544 while(my $line = <>){
545         chomp $line;
546         if($line eq "1"){
547                 last;
548         } elsif($line eq "2"){
549                 $compiler_flags = "-g -O0";
550                 last;
551         } elsif($line eq "4" ){
552                 $compiler_flags = "--with-production --enable-tracing";
553                 last;
554         } elsif($line eq "3" || $line eq ""){
555                 $compiler_flags = "--with-production";
556                 last;
557         }  elsif($line eq "5"){
558
559                 print "Enter compiler options: ";
560                 my $input_line = <>;
561                 chomp($input_line);
562                 $compiler_flags = $input_line;
563
564                 last;
565         } else {
566                 print "Invalid option, please try again :P\n"
567         }
568 }
569
570
571
572
573 # Determine the target to build.
574 # We want this simple so we just give 2 options
575 my $target = "";
576
577 print << "EOF";
578
579 What do you want to build?
580         1) Charm++ [default] (choose this if you are building NAMD)
581         2) Charm++ and AMPI
582         3) Charm++, AMPI, ParFUM, FEM and other libraries
583
584 EOF
585
586 while(my $line = <>){
587         chomp $line;
588         if($line eq "1" || $line eq ""){
589                 $target = "charm++";
590                 last;
591         } elsif($line eq "2"){
592                 $target = "AMPI";
593                 last;
594         } elsif($line eq "3"){
595                 $target = "LIBS";
596                 last;
597         } else {
598                 print "Invalid option, please try again :P\n"
599         }
600
601 }
602
603 # Determine whether to use a -j flag for faster building
604 my $j = "";
605     print << "EOF";
606
607 Do you want to compile in parallel?
608         1) No
609         2) Build with -j2
610         3) Build with -j4
611         4) Build with -j8
612         5) Build with -j16 [default]
613         6) Build with -j32
614         7) Build with -j
615
616 EOF
617
618     while(my $line = <>) {
619         chomp $line;
620         if($line eq "1"){
621             $j = "";
622             last;
623         } elsif($line eq "2") {
624             $j = "-j2";
625             last;
626         } elsif($line eq "3") {
627             $j = "-j4";
628             last;
629         }  elsif($line eq "4") {
630             $j = "-j8";
631             last;
632         }  elsif($line eq "5" || $line eq "") {
633             $j = "-j16";
634             last;
635         }  elsif($line eq "6") {
636             $j = "-j32";
637             last;
638         }  elsif($line eq "7") {
639             $j = "-j";
640             last;
641         }   else {
642             print "Invalid option, please try again :P\n";
643         }
644 }
645
646
647 # Compose the build line
648 my $build_line = "$dirname/build $target $arch $compilers $options $j $nobs ${compiler_flags}\n";
649
650
651 # Save the build line in the log
652 open(BUILDLINE, ">>smart-build.log");
653 print BUILDLINE `date`;
654 print BUILDLINE "Using the following build command:\n";
655 print BUILDLINE "$build_line\n";
656 close(BUILDLINE);
657
658
659 print "We have determined a suitable build line is:\n";
660 print "\t$build_line\n\n";
661
662
663 # Execute the build line if the appropriate architecture directory exists
664 print "Do you want to start the build now? [Y/n]: ";
665 my $p = promptUserYN();
666 if($p eq "yes" || $p eq "default"){
667   if(-e "$dirname/src/arch/$arch"){
668         print "Building with: ${build_line}\n";
669         # Execute the build line
670         system($build_line);
671   } else {
672         print "We could not figure out how to build charm with those options on this platform, please manually build\n";
673         print "Try something similar to: ${build_line}\n";
674   }
675 }
676
677
678