mpi.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/time.h>
  4. #include <sys/types.h>
  5. #include <sys/resource.h>
  6. #include <sys/wait.h>
  7. #include <fcntl.h>
  8. #include <errno.h>
  9. #include <mpi.h>
  10. #include <NTL/ZZ.h>
  11. #include "controller.h"
  12. #include "worker.h"
  13. #include "dpnode.h"
  14. NTL_CLIENT
  15. static int mpi_size;
  16. static int controllerfds[2];
  17. // Close fds 3 and up, except for the one given (pass -1 to close them
  18. // all)
  19. static void close_highfds_except(rlim_t exceptfd)
  20. {
  21. // Find the max fd number
  22. struct rlimit limit;
  23. getrlimit(RLIMIT_NOFILE, &limit);
  24. for (rlim_t fd = 3; fd < limit.rlim_cur; ++fd) {
  25. if (fd != exceptfd) {
  26. // There's no ill effect from closing a non-open fd, so just
  27. // do it
  28. close(fd);
  29. }
  30. }
  31. }
  32. static void boundcb(const char *boundaddr, unsigned short boundport)
  33. {
  34. // Write the port and addr to the pipe
  35. write(controllerfds[1], &boundport, 2);
  36. write(controllerfds[1], boundaddr, strlen(boundaddr));
  37. close(controllerfds[1]);
  38. }
  39. void desired_resources(const ZZ &order, unsigned short &desired_dpnodes,
  40. unsigned int &max_workers, unsigned int &dpfreq)
  41. {
  42. // How many DPnodes should we use for a problem of this size?
  43. desired_dpnodes = 1;
  44. // How many workers would we like to use?
  45. ZZ sorder = SqrRoot(order >> 46);
  46. if (NumBits(sorder) > 30) {
  47. // Just use all the workers we can find
  48. max_workers = 4294967295U; // 2^32 - 1
  49. } else {
  50. max_workers = trunc_long(sorder,31) + 1;
  51. }
  52. // By default, 1 in 1000 points are distinguihed points. The
  53. // number in the next line is 2^32/1000
  54. dpfreq = 4294967;
  55. if (order < 1000) {
  56. // Just make every point a DP
  57. dpfreq = 4294967295U;
  58. } else if (NumBits(order) < 27) {
  59. // The frequency of DPs should be 10/sqrt(order) to avoid
  60. // a DP-free cycle, so dpfreq = (10*2^32)/sqrt(order)
  61. ZZ f = (to_ZZ(10) << 32) / SqrRoot(order);
  62. dpfreq = trunc_long(f, 31);
  63. }
  64. }
  65. void redirect_output(const char* dir, const char* filename_base, int rank_index, int process_index, const char* filename_ext){
  66. // redirect stdout and stderr to a file
  67. char buf[512];
  68. snprintf(buf, sizeof(buf), "%s/%s_%d_%d.%s", dir, filename_base, rank_index, process_index, filename_ext);
  69. int fd = open(buf, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
  70. dup2(fd, 1);
  71. dup2(fd, 2);
  72. close(fd);
  73. }
  74. static pid_t fork_and_remember(vector<pid_t> &children)
  75. {
  76. pid_t pid = fork();
  77. if (pid > 0) {
  78. children.push_back(pid);
  79. }
  80. return pid;
  81. }
  82. int main(int argc, char **argv)
  83. {
  84. // Init MPI
  85. MPI_Init(&argc, &argv);
  86. if (argc < 4) {
  87. printf("You must pass at least three arguments:\n");
  88. printf(" 1) number of workers to start per node/rank\n");
  89. printf(" 2) number of dpnodes to start per node/rank\n");
  90. printf(" 3) directory to store output files (stdout+stderr)\n");
  91. printf("The remaining arguments will be passed to the controller.\n");
  92. MPI_Finalize();
  93. exit(1);
  94. }
  95. char hostname[257];
  96. gethostname(hostname, 256);
  97. vector<pid_t> children;
  98. int rank = 0;
  99. int ret = 0;
  100. MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  101. MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
  102. char boundportaddr[259];
  103. unsigned int num_workers = strtol(argv[1], NULL, 10);
  104. unsigned int num_dpnodes = strtol(argv[2], NULL, 10);
  105. if (rank == 0) {
  106. // Start the controller
  107. pipe(controllerfds);
  108. char fdenv[30];
  109. sprintf(fdenv, "%d", controllerfds[1]);
  110. setenv("CONTROLLER_BOUNDCB_FD", fdenv, 1);
  111. if (fork_and_remember(children) == 0) {
  112. // Child; close the read half of the pipe and all other fds
  113. close_highfds_except(controllerfds[1]);
  114. char name[] = "controller";
  115. argv[3] = name;
  116. execv("./controller", argv+3);
  117. return 1;
  118. } else {
  119. // Parent; close the write half of the pipe
  120. close(controllerfds[1]);
  121. int res;
  122. memset(boundportaddr, '\0', 259);
  123. res = read(controllerfds[0], boundportaddr, 2);
  124. if (res < 2) return 1;
  125. res = read(controllerfds[0], boundportaddr+2, 256);
  126. if (res < 1) return 1;
  127. close(controllerfds[0]);
  128. // std::cerr << "Parent reports controller bound to " << boundaddr << ":" << boundport << "\n";
  129. }
  130. }
  131. MPI_Bcast(boundportaddr, 259, MPI_CHAR, 0, MPI_COMM_WORLD);
  132. unsigned short boundport;
  133. memmove(&boundport, boundportaddr, 2);
  134. char portstr[10];
  135. sprintf(portstr, "%hu", boundport);
  136. const char *boundaddr = boundportaddr + 2;
  137. // The child will spawn its own children to be the workers
  138. for (unsigned int i=0; i<num_workers; i++) {
  139. if (fork_and_remember(children) == 0) {
  140. close_highfds_except(-1);
  141. redirect_output(argv[3], "worker", rank, i, "out");
  142. char gpu_index[10];
  143. snprintf(gpu_index, 10, "%d", i);
  144. execl("./worker", "./worker", boundaddr, portstr, gpu_index, NULL);
  145. return 1;
  146. }
  147. }
  148. // And dpnodes
  149. for (unsigned int i=0; i<num_dpnodes; i++) {
  150. if (fork_and_remember(children) == 0) {
  151. close_highfds_except(-1);
  152. redirect_output(argv[3], "dpnode", rank, i, "out");
  153. execl("./dpnode", "./dpnode", boundaddr, portstr, NULL);
  154. return 1;
  155. }
  156. }
  157. // Now wait for all the children
  158. vector<pid_t>::iterator pidit;
  159. for (pidit = children.begin(); pidit != children.end(); ++pidit) {
  160. int status;
  161. waitpid(*pidit, &status, 0);
  162. }
  163. MPI_Finalize();
  164. return ret;
  165. }