dpnode.cc 11 KB

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