dpnode.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. extern "C" {
  2. #include <event2/listener.h>
  3. #include <event2/bufferevent.h>
  4. #include <event2/buffer.h>
  5. #include <event2/util.h>
  6. }
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <set>
  11. #include <unordered_map>
  12. #ifdef LOG_MEM
  13. #include <stdio.h>
  14. #endif
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <sstream>
  19. #include <fstream>
  20. #include "evutils.h"
  21. #include "subproblem.h"
  22. #include "dpnode.h"
  23. // #undef VERBOSE
  24. #ifdef SAVE_DPS
  25. static ofstream dp_file_stream;
  26. #endif
  27. typedef unordered_map<std::string, pair<ZZ,ZZ> > DTable;
  28. typedef enum {
  29. DPSTATE_START,
  30. DPSTATE_END
  31. } DPState;
  32. struct DPNodeConnInfo {
  33. DPState state;
  34. DPNodeConnInfo() : state(DPSTATE_START) {}
  35. };
  36. static struct DPControllerState {
  37. struct bufferevent *controller_bev;
  38. Subproblem *current_problem;
  39. struct evconnlistener *listener;
  40. std::set<struct bufferevent *> workers;
  41. DTable table;
  42. unsigned long long numdps;
  43. unsigned int id;
  44. DPControllerState() : controller_bev(NULL), current_problem(NULL),
  45. listener(NULL), id(0) {}
  46. } dpctrlstate;
  47. #ifdef LOG_MEM
  48. /* Log the amount of memory used by the process. It turns out each DP
  49. consumes about 338 bytes of heap. Also, memory is not deallocated when
  50. the table is cleared. */
  51. static void logmemusage(const char *label)
  52. {
  53. FILE *smaps;
  54. FILE *logoutput;
  55. char logfilename[256];
  56. sprintf(logfilename, "mem-%05d", getpid());
  57. smaps = fopen("/proc/self/smaps", "r");
  58. if (!smaps) return;
  59. logoutput = fopen(logfilename, "a");
  60. if (!logoutput) {
  61. fclose(smaps);
  62. return;
  63. }
  64. char *line = NULL;
  65. size_t n = 0;
  66. while(getline(&line, &n, smaps) > -1) {
  67. if (!strstr(line, "[heap]")) {
  68. free(line);
  69. line = NULL;
  70. continue;
  71. }
  72. // Read and parse the next line
  73. if (getline(&line, &n, smaps) > -1 && !strncmp(line, "Size:", 5)) {
  74. unsigned long usage;
  75. if (sscanf(line+5, "%lu", &usage) == 1) {
  76. fprintf(logoutput, "%s %lu %lu %lu\n", label,
  77. dpctrlstate.table.size(), dpctrlstate.table.max_size(),
  78. usage);
  79. break;
  80. }
  81. }
  82. }
  83. fclose(logoutput);
  84. fclose(smaps);
  85. }
  86. #endif
  87. static void dpnode_event_cb(struct bufferevent *bev, short events,
  88. void *ctx)
  89. {
  90. if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  91. #ifdef VERBOSE
  92. cerr << "Closing connection " << bev << " ";
  93. if (events & BEV_EVENT_EOF) {
  94. cerr << "EOF";
  95. }
  96. if (events & BEV_EVENT_ERROR) {
  97. cerr << "ERR (" << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()) << ")";
  98. }
  99. cerr << "\n";
  100. #endif
  101. DPNodeConnInfo *info = (DPNodeConnInfo*)ctx;
  102. delete info;
  103. dpctrlstate.workers.erase(bev);
  104. bufferevent_free(bev);
  105. }
  106. }
  107. static void stop_problem(void);
  108. static void dpnode_reader(struct bufferevent *bev, void *ctx)
  109. {
  110. struct evbuffer *input = bufferevent_get_input(bev);
  111. unsigned int dp[WORDS+6];
  112. while(1) {
  113. size_t len = evbuffer_get_length(input);
  114. if (len < ((WORDS+6)*sizeof(unsigned int))) break;
  115. bufferevent_read(bev, dp, (WORDS+6)*sizeof(unsigned int));
  116. if (dpctrlstate.current_problem == NULL) continue;
  117. // The (WORDS+6) unsigned ints we read are:
  118. // - WORDS words for the value of the dp
  119. // - 3 words for a
  120. // - 3 words for b
  121. ZZ zz_a, zz_b;
  122. ZZFromBytes(zz_a, (const unsigned char *)(dp+WORDS),
  123. 3*sizeof(unsigned int));
  124. ZZFromBytes(zz_b, (const unsigned char *)(dp+WORDS+3),
  125. 3*sizeof(unsigned int));
  126. string x((const char *)(dp), WORDS*sizeof(unsigned int));
  127. pair<ZZ,ZZ> ab(zz_a,zz_b);
  128. #ifdef SAVE_DPS
  129. ZZ zz_x;
  130. ZZFromBytes(zz_x, (const unsigned char *)(dp),
  131. WORDS*sizeof(unsigned int));
  132. dp_file_stream << zz_x << "\n";
  133. #endif
  134. pair<DTable::iterator, bool> res =
  135. dpctrlstate.table.insert(DTable::value_type(x,ab));
  136. #ifdef LOG_MEM
  137. if (dpctrlstate.table.size() % 1000 == 0) {
  138. logmemusage("insert");
  139. }
  140. #endif
  141. if (!res.second) {
  142. const ZZ& order = dpctrlstate.current_problem->order;
  143. // Collision!
  144. ZZ adiff = res.first->second.first - zz_a;
  145. ZZ bdiff = zz_b - res.first->second.second;
  146. while (bdiff < 0) bdiff += order;
  147. while (bdiff >= order) bdiff -= order;
  148. while (adiff < 0) adiff += order;
  149. while (adiff >= order) adiff -= order;
  150. ZZ binv;
  151. if (InvModStatus(binv, bdiff, order) == 0) {
  152. ZZ expon = MulMod(binv, adiff, order);
  153. #ifdef VERBOSE
  154. cerr << "Collision after " << dpctrlstate.numdps << " DPs\n";
  155. #endif
  156. unsigned char exponbytes[3+3*sizeof(unsigned int)];
  157. exponbytes[0] = 'E';
  158. memmove(exponbytes+1,
  159. &(dpctrlstate.current_problem->problemid), 2);
  160. BytesFromZZ(exponbytes+3, expon, 3*sizeof(unsigned int));
  161. bufferevent_write(dpctrlstate.controller_bev, exponbytes,
  162. 3+3*sizeof(unsigned int));
  163. stop_problem();
  164. return;
  165. }
  166. }
  167. ++dpctrlstate.numdps;
  168. }
  169. }
  170. static void dpnode_accept_cb(struct evconnlistener *listener,
  171. evutil_socket_t fd, struct sockaddr *address, int socklen,
  172. void *ctx)
  173. {
  174. DPNodeConnInfo *info = new DPNodeConnInfo();
  175. // Create a bufferevent for the new connection
  176. struct event_base *base = evconnlistener_get_base(listener);
  177. struct bufferevent *bev = bufferevent_socket_new(
  178. base, fd, BEV_OPT_CLOSE_ON_FREE);
  179. #ifdef VERBOSE
  180. cerr << "accepted connection " << bev << "\n";
  181. #endif
  182. bufferevent_setcb(bev, dpnode_reader, NULL,
  183. dpnode_event_cb, info);
  184. bufferevent_enable(bev, EV_READ);
  185. dpctrlstate.workers.insert(bev);
  186. }
  187. // Create a new DPnode socket. ip and boundport are set to the IP and
  188. // port of the socket, in network byte order.
  189. struct evconnlistener *dpnode_create(struct event_base *evbase,
  190. unsigned int *ip, unsigned short *boundport)
  191. {
  192. struct evconnlistener *ecl = listener_create(evbase, 0,
  193. dpnode_accept_cb, NULL, ip, boundport, false);
  194. #ifdef VERBOSE
  195. cerr << "Listening at " << ecl << "\n";
  196. #endif
  197. return ecl;
  198. }
  199. typedef enum {
  200. DPCCSTATE_AWAITCMD,
  201. DPCCSTATE_RDID,
  202. DPCCSTATE_RDPROBLEM,
  203. DPCCSTATE_END
  204. } DPCCState;
  205. struct DPControllerConnInfo {
  206. DPCCState state;
  207. DPControllerConnInfo() : state(DPCCSTATE_AWAITCMD) {}
  208. };
  209. static void stop_problem(void)
  210. {
  211. #ifdef VERBOSE
  212. cerr << "Stopping problem\n";
  213. #endif
  214. #ifdef SAVE_DPS
  215. dp_file_stream.close();
  216. #endif
  217. if (dpctrlstate.current_problem) {
  218. delete dpctrlstate.current_problem;
  219. dpctrlstate.current_problem = NULL;
  220. }
  221. if (dpctrlstate.listener) {
  222. #ifdef VERBOSE
  223. cerr << "Closing listener " << dpctrlstate.listener << "\n";
  224. #endif
  225. evconnlistener_free(dpctrlstate.listener);
  226. dpctrlstate.listener = NULL;
  227. }
  228. std::set<struct bufferevent *>::iterator wit;
  229. for (wit = dpctrlstate.workers.begin(); wit != dpctrlstate.workers.end();
  230. ++wit) {
  231. #ifdef VERBOSE
  232. cerr << "Closing connection " << *wit << "\n";
  233. #endif
  234. bufferevent_free(*wit);
  235. }
  236. dpctrlstate.workers.clear();
  237. #ifdef LOG_MEM
  238. logmemusage("preclear");
  239. #endif
  240. dpctrlstate.table.clear();
  241. #ifdef LOG_MEM
  242. logmemusage("postclear");
  243. #endif
  244. dpctrlstate.numdps = 0;
  245. }
  246. static void start_problem(struct bufferevent *bev,
  247. const unsigned char *subproblem)
  248. {
  249. unsigned int myip;
  250. unsigned short myport;
  251. stop_problem();
  252. dpctrlstate.current_problem = new Subproblem(subproblem);
  253. #ifdef VERBOSE
  254. dpctrlstate.current_problem->dump(cerr);
  255. #endif
  256. #ifdef SAVE_DPS
  257. std::ostringstream oss;
  258. oss << "dplist_" << dpctrlstate.id << "_" << dpctrlstate.current_problem->problemid << ".out";
  259. dp_file_stream.open(oss.str().c_str());
  260. dp_file_stream << "Subproblem " << dpctrlstate.current_problem->problemid << "\n";
  261. #endif
  262. // Create the DPNode server socket
  263. dpctrlstate.listener = dpnode_create(bufferevent_get_base(bev),
  264. &myip, &myport);
  265. #ifdef VERBOSE
  266. struct in_addr myaddr = { myip };
  267. fprintf(stderr, "Bound to %s:%d\n", inet_ntoa(myaddr), ntohs(myport));
  268. #endif
  269. unsigned char idstring[7];
  270. idstring[0] = 'L';
  271. memmove(idstring+1, &myip, 4);
  272. memmove(idstring+5, &myport, 2);
  273. bufferevent_write(bev, idstring, 7);
  274. }
  275. static void controllerconn_reader(struct bufferevent *bev, void *ctx)
  276. {
  277. struct evbuffer *input = bufferevent_get_input(bev);
  278. DPControllerConnInfo *info = (DPControllerConnInfo *)ctx;
  279. unsigned char cmd[1];
  280. unsigned char subproblem[SUBPROBLEM_DESC_LEN];
  281. while(1) {
  282. size_t len = evbuffer_get_length(input);
  283. switch(info->state) {
  284. case DPCCSTATE_AWAITCMD:
  285. if (len < 1) return;
  286. bufferevent_read(bev, cmd, 1);
  287. #ifdef VERBOSE
  288. cerr << "Received command " << cmd[0] << "\n";
  289. #endif
  290. switch(cmd[0]) {
  291. case 'I':
  292. info->state = DPCCSTATE_RDID;
  293. break;
  294. case 'P':
  295. info->state = DPCCSTATE_RDPROBLEM;
  296. break;
  297. case 'S':
  298. stop_problem();
  299. break;
  300. default:
  301. /* Unknown command received */
  302. fprintf(stderr, "Unknown command in "
  303. "controllerconn_reader: %c\n", cmd[0]);
  304. info->state = DPCCSTATE_END;
  305. break;
  306. }
  307. break;
  308. case DPCCSTATE_RDID:
  309. if (len < sizeof(unsigned int)) return;
  310. unsigned int dpnode_id;
  311. bufferevent_read(bev, &dpnode_id, sizeof(unsigned int));
  312. dpctrlstate.id = dpnode_id;
  313. info->state = DPCCSTATE_AWAITCMD;
  314. break;
  315. case DPCCSTATE_RDPROBLEM:
  316. if (len < SUBPROBLEM_DESC_LEN) return;
  317. bufferevent_read(bev, subproblem, SUBPROBLEM_DESC_LEN);
  318. start_problem(bev, subproblem);
  319. info->state = DPCCSTATE_AWAITCMD;
  320. break;
  321. case DPCCSTATE_END:
  322. // Shut down
  323. delete info;
  324. event_base_loopbreak(bufferevent_get_base(bev));
  325. #ifdef VERBOSE
  326. cerr << "END conenction " << bev << "\n";
  327. #endif
  328. dpctrlstate.workers.erase(bev);
  329. bufferevent_free(bev);
  330. return;
  331. }
  332. }
  333. }
  334. static void controllerconn_event_cb(struct bufferevent *bev, short events,
  335. void *ctx)
  336. {
  337. if (events & BEV_EVENT_CONNECTED) {
  338. // We have successfully connected to the controller
  339. char id[1] = { 'D' };
  340. bufferevent_enable(bev, EV_READ|EV_WRITE);
  341. bufferevent_write(bev, id, 1);
  342. bufferevent_setcb(bev, controllerconn_reader, NULL,
  343. controllerconn_event_cb, new DPControllerConnInfo());
  344. dpctrlstate.controller_bev = bev;
  345. } else if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  346. #ifdef VERBOSE
  347. fprintf(stderr, "Closing connection to controller and exiting\n");
  348. #endif
  349. event_base_loopbreak(bufferevent_get_base(bev));
  350. bufferevent_free(bev);
  351. }
  352. }
  353. int dpnode_main(const char *controller_host, unsigned short controller_port)
  354. {
  355. return controller_client(controller_host, controller_port,
  356. controllerconn_event_cb, false);
  357. }