mpi.cc 4.1 KB

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