worker.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include <pthread.h>
  2. extern "C" {
  3. #include <event2/thread.h>
  4. #include <event2/bufferevent.h>
  5. #include <event2/buffer.h>
  6. #include <event2/event.h>
  7. }
  8. #include <NTL/ZZ_p.h>
  9. #include <vector>
  10. #include <stdio.h>
  11. #include "cudadl.h"
  12. #include "evutils.h"
  13. #include "subproblem.h"
  14. NTL_CLIENT
  15. typedef enum {
  16. WRKCCSTATE_AWAITCMD,
  17. WRKCCSTATE_RDPROBLEM,
  18. WRKCCSTATE_RDDPNODES,
  19. WRKCCSTATE_END
  20. } WrkCCState;
  21. struct WrkControllerConnInfo {
  22. WrkCCState state;
  23. unsigned short num_dpnodes;
  24. WrkControllerConnInfo() : state(WRKCCSTATE_AWAITCMD), num_dpnodes(0) {}
  25. };
  26. typedef enum { WT_NOT_RUNNING, WT_RUNNING, WT_SHOULD_STOP} WTState;
  27. static struct WrkControllerState {
  28. Subproblem *current_problem;
  29. unsigned short num_expected_dpnodes;
  30. vector<struct bufferevent *> dpnodes;
  31. unsigned short num_connected_dpnodes;
  32. WTState worker_thread_state;
  33. pthread_t worker_thread;
  34. WrkControllerState(): current_problem(NULL),
  35. worker_thread_state(WT_NOT_RUNNING) {}
  36. } wrkctrlstate;
  37. // ----- Below this line are the functions running in the worker thread.
  38. #if WORDS > 1
  39. #define DEMUXWORD 8
  40. #else
  41. #define DEMUXWORD 7
  42. #endif
  43. // This function is called from inside cuda_dl for each DP it encounters.
  44. // It calls the function named "dpcallback" directly. It would be
  45. // cleaner if this were passed as a function pointer to cuda_dl, but
  46. // that makes nvcc 3.1 segfault. :-p
  47. // dp points to an array of WORDS+7 unsigned ints:
  48. // - 1 word of threadID/blockID
  49. // - WORDS words of the dp value
  50. // - 3 words of a
  51. // - 3 words of b
  52. bool dpcallback(void *cbdata, unsigned int *dpwords)
  53. {
  54. unsigned int demux = dpwords[DEMUXWORD];
  55. struct bufferevent *bev =
  56. wrkctrlstate.dpnodes[demux % wrkctrlstate.num_connected_dpnodes];
  57. bufferevent_write(bev, dpwords+1, (WORDS+6)*sizeof(unsigned int));
  58. // If worker_thread_state changes to WT_SHOULD_STOP, then signal to
  59. // stop computation by returning true. If for some reason, it
  60. // becomes WT_NOT_RUNNING (which it shouldn't), stop as well.
  61. return wrkctrlstate.worker_thread_state != WT_RUNNING;
  62. }
  63. static void *worker_thread_start(void *data)
  64. {
  65. ZZ_p::init(wrkctrlstate.current_problem->modulus);
  66. cuda_dl(to_ZZ_p(wrkctrlstate.current_problem->base),
  67. to_ZZ_p(wrkctrlstate.current_problem->target),
  68. wrkctrlstate.current_problem->order,
  69. wrkctrlstate.current_problem->modulus,
  70. wrkctrlstate.current_problem->dpfreq, NULL);
  71. return NULL;
  72. }
  73. // ----- Above this line are the functions running in the worker thread.
  74. // Below are the functions running in the main (communication) thread.
  75. static void stop_working(void)
  76. {
  77. cerr << "Stopping work\n";
  78. if (wrkctrlstate.worker_thread_state != WT_NOT_RUNNING) {
  79. // Tell the worker thread to stop after its next kernel launch
  80. wrkctrlstate.worker_thread_state = WT_SHOULD_STOP;
  81. pthread_join(wrkctrlstate.worker_thread, NULL);
  82. wrkctrlstate.worker_thread_state = WT_NOT_RUNNING;
  83. }
  84. // Close the connections to the dpnodes
  85. vector<struct bufferevent *>::iterator bevit;
  86. for (bevit = wrkctrlstate.dpnodes.begin();
  87. bevit != wrkctrlstate.dpnodes.end(); ++bevit) {
  88. bufferevent_free(*bevit);
  89. }
  90. wrkctrlstate.dpnodes.clear();
  91. wrkctrlstate.num_connected_dpnodes = 0;
  92. wrkctrlstate.num_expected_dpnodes = 0;
  93. // Careful! Subproblem uses NTL, so we must be sure we're not
  94. // multithreaded at this point.
  95. delete wrkctrlstate.current_problem;
  96. wrkctrlstate.current_problem = NULL;
  97. }
  98. static void start_working(void)
  99. {
  100. cerr << "Starting work\n";
  101. wrkctrlstate.worker_thread_state = WT_RUNNING;
  102. if (pthread_create(&wrkctrlstate.worker_thread, NULL,
  103. worker_thread_start, NULL)) {
  104. wrkctrlstate.worker_thread = WT_NOT_RUNNING;
  105. cerr << "Could not start worker thread\n";
  106. }
  107. }
  108. static void dpconn_event_cb(struct bufferevent *bev, short events,
  109. void *ctx)
  110. {
  111. if (events & BEV_EVENT_CONNECTED) {
  112. // We have successfully connected to the dpnode
  113. bufferevent_enable(bev, EV_WRITE);
  114. ++wrkctrlstate.num_connected_dpnodes;
  115. if (wrkctrlstate.num_connected_dpnodes ==
  116. wrkctrlstate.num_expected_dpnodes) {
  117. start_working();
  118. }
  119. } else if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  120. fprintf(stderr, "Closing connection to dpnode\n");
  121. stop_working();
  122. bufferevent_free(bev);
  123. }
  124. }
  125. static void controllerconn_reader(struct bufferevent *bev, void *ctx)
  126. {
  127. struct evbuffer *input = bufferevent_get_input(bev);
  128. WrkControllerConnInfo *info = (WrkControllerConnInfo *)ctx;
  129. unsigned char cmd[1];
  130. unsigned char subproblem[SUBPROBLEM_DESC_LEN];
  131. while(1) {
  132. size_t len = evbuffer_get_length(input);
  133. switch(info->state) {
  134. case WRKCCSTATE_AWAITCMD:
  135. if (len < 1) return;
  136. bufferevent_read(bev, cmd, 1);
  137. switch(cmd[0]) {
  138. case 'P':
  139. info->state = WRKCCSTATE_RDPROBLEM;
  140. break;
  141. case 'S':
  142. stop_working();
  143. break;
  144. default:
  145. /* Unknown command received */
  146. fprintf(stderr, "Unknown command in "
  147. "controllerconn_reader: %c\n", cmd[0]);
  148. info->state = WRKCCSTATE_END;
  149. break;
  150. }
  151. break;
  152. case WRKCCSTATE_RDPROBLEM:
  153. if (len < SUBPROBLEM_DESC_LEN+2) return;
  154. stop_working();
  155. bufferevent_read(bev, subproblem, SUBPROBLEM_DESC_LEN);
  156. bufferevent_read(bev, &(info->num_dpnodes), 2);
  157. // Careful! Subproblem uses NTL, so we must be sure
  158. // we're not multithreaded at this point.
  159. wrkctrlstate.current_problem = new Subproblem(subproblem);
  160. info->state = WRKCCSTATE_RDDPNODES;
  161. /* FALLTHROUGH */
  162. case WRKCCSTATE_RDDPNODES:
  163. if (len < 6*(info->num_dpnodes)) return;
  164. wrkctrlstate.num_expected_dpnodes = info->num_dpnodes;
  165. {
  166. unsigned short i;
  167. for(i=0;i<info->num_dpnodes;++i) {
  168. unsigned char ipport[6];
  169. bufferevent_read(bev, ipport, 6);
  170. cerr << "Connecting to DPnode " <<
  171. int(ipport[0]) << "." <<
  172. int(ipport[1]) << "." <<
  173. int(ipport[2]) << "." <<
  174. int(ipport[3]) << ":" <<
  175. ((ipport[4] << 8) + ipport[5]) <<
  176. "\n";
  177. struct bufferevent *dpbev = client_create(
  178. bufferevent_get_base(bev), ipport,
  179. dpconn_event_cb, true);
  180. if (dpbev) {
  181. wrkctrlstate.dpnodes.push_back(dpbev);
  182. } else {
  183. stop_working();
  184. }
  185. }
  186. }
  187. info->state = WRKCCSTATE_AWAITCMD;
  188. break;
  189. case WRKCCSTATE_END:
  190. // Shut down
  191. delete info;
  192. event_base_loopbreak(bufferevent_get_base(bev));
  193. bufferevent_free(bev);
  194. return;
  195. }
  196. }
  197. }
  198. static void controllerconn_event_cb(struct bufferevent *bev, short events,
  199. void *ctx)
  200. {
  201. if (events & BEV_EVENT_CONNECTED) {
  202. // We have successfully connected to the controller
  203. char id[1] = { 'W' };
  204. bufferevent_enable(bev, EV_READ|EV_WRITE);
  205. bufferevent_write(bev, id, 1);
  206. bufferevent_setcb(bev, controllerconn_reader, NULL,
  207. controllerconn_event_cb, new WrkControllerConnInfo());
  208. } else if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  209. fprintf(stderr, "Closing connection to controller and exiting\n");
  210. event_base_loopbreak(bufferevent_get_base(bev));
  211. bufferevent_free(bev);
  212. }
  213. }
  214. int main(int argc, char **argv)
  215. {
  216. if (argc != 3) {
  217. fprintf(stderr, "Usage: %s controller_host controller_port\n", argv[0]);
  218. return 1;
  219. }
  220. unsigned short controller_port = strtoul(argv[2], NULL, 10);
  221. evthread_use_pthreads();
  222. return controller_client(argv[1], controller_port,
  223. controllerconn_event_cb, true);
  224. }