//------------------------------------------------------------------------------ int pop(Workers& workers) { assert(workers.size() > 0); std::set< worker_info >::iterator back = --workers.end(); const int ret = back->id(); workers.erase(back); return ret; }
inline unit_t getCount() const throw() { unit_t count = 0; for(size_t i=workers.size();i>0;--i) { count += workers[i]->count; } return count; }
void saveXYZ( ios::ostream &fp ) const { unsigned np = 0; const size_t nw = workers.size(); for(size_t i=nw;i>0;--i) { np += workers[i]->running.size; } fp("%u\n", np); fp("\n"); for(size_t i=nw;i>0;--i) { for(const Particle *p=workers[i]->running.head;p;p=p->next) { const char *id = "H"; if(p->kind) id = "Li"; fp("%s %g %g %g\n",id,p->r.x,p->r.y,p->r.z); } } }
inline void setup() throw() { // gather particles const size_t nw = workers.size(); running.merge_back(waiting); for(size_t i=nw;i>0;--i) { running.merge_back(workers[i]->running); running.merge_back(workers[i]->waiting); } core::merging<Particle>::sort(running, Particle::compareByAddress, NULL); // initialize them for(Particle *p=running.head;p;p=p->next) { p->r.x = -Box.x/2 + Box.x * ran(); p->r.y = -Box.y/2 + Box.y * ran(); p->r.z = -Box.z * ran(); p->status = Particle::InReservoir; p->kind = 0; p->inReservoir(); } // dispatch particles const size_t np = running.size; for(size_t i=0;i<nw;++i) { size_t offset = 0; size_t length = np; parallel::basic_split(i,nw, offset, length); Worker &w = *workers[i+1]; while(length-->0) { w.running.push_back(running.pop_front()); } //std::cerr << "#running[" << i+1 << "]=" << w.running.size << std::endl; } }
//------------------------------------------------------------------------------ int main(int argc, char** argv) { if(argc < 3) { std::cout << "usage: " << argv[0] << " <frontend address> <backend address>" << std::endl; return 0; } const char* FRONTEND_URI = argv[1]; const char* BACKEND_URI = argv[2]; const int MAX_REQUESTS = 100; //create communication objects void* context = zmq_ctx_new(); assert(context); void* frontend = zmq_socket(context, ZMQ_ROUTER); assert(frontend); void* backend = zmq_socket(context, ZMQ_ROUTER); assert(backend); assert(zmq_bind(frontend, FRONTEND_URI) == 0); assert(zmq_bind(backend, BACKEND_URI) == 0); //workers ordered queue Workers workers; int worker_id = -1; int client_id = -1; int rc = -1; std::vector< char > request(0x100, 0); std::vector< char > reply(0x100, 0); int serviced_requests = 0; //loop until max requests servided while(serviced_requests < MAX_REQUESTS) { zmq_pollitem_t items[] = { {backend, 0, ZMQ_POLLIN, 0}, {frontend, 0, ZMQ_POLLIN, 0}}; //remove all workers that have not been active for a //time > expiration interval //XXX TODO: TEST purge(workers, EXPIRATION_INTERVAL); //XXX //poll for incoming requests: if no workers are available //only poll for workers(backend) since there is no point //in trying to service a client request without active //workers rc = zmq_poll(items, workers.size() > 0 ? 2 : 1, TIMEOUT); if(rc == -1) break; //data from workers if(items[0].revents & ZMQ_POLLIN) { assert(zmq_recv(backend, &worker_id, sizeof(worker_id), 0) > 0); assert(zmq_recv(backend, 0, 0, 0) == 0); assert(zmq_recv(backend, &client_id, sizeof(client_id), 0) > 0); //add worker to list of available workers push(workers, worker_id); assert(workers.size() > 0); //of not a 'ready' message forward message to frontend //workers send 'ready' messages when either if(client_id != WORKER_READY) { int seq_id = -1; assert(zmq_recv(backend, 0, 0, 0) == 0); rc = zmq_recv(backend, &seq_id, sizeof(seq_id), 0); assert(rc > 0); rc = zmq_recv(backend, &reply[0], reply.size(), 0); assert(rc > 0); zmq_send(frontend, &client_id, sizeof(client_id), ZMQ_SNDMORE); zmq_send(frontend, 0, 0, ZMQ_SNDMORE); zmq_send(frontend, &seq_id, sizeof(seq_id), ZMQ_SNDMORE); zmq_send(frontend, &reply[0], rc, 0); ++serviced_requests; } } //request from clients if(items[1].revents & ZMQ_POLLIN) { int seq_id = -1; //receive request |client id|<null>|request id|data| zmq_recv(frontend, &client_id, sizeof(client_id), 0); zmq_recv(frontend, 0, 0, 0); rc = zmq_recv(frontend, &seq_id, sizeof(seq_id), 0); assert(rc > 0); const int req_size = zmq_recv(frontend, &request[0], request.size(), 0); assert(req_size > 0); //take worker from list and forward request to it worker_id = pop(workers); assert(worker_id > 0); zmq_send(backend, &worker_id, sizeof(worker_id), ZMQ_SNDMORE); zmq_send(backend, 0, 0, ZMQ_SNDMORE); zmq_send(backend, &client_id, sizeof(client_id), ZMQ_SNDMORE); zmq_send(backend, 0, 0, ZMQ_SNDMORE); zmq_send(backend, &seq_id, sizeof(seq_id), ZMQ_SNDMORE); zmq_send(backend, &request[0], req_size, 0); } const int hb = HEARTBEAT; //capturing HEARTBEAT directly generates //a warning because the lambda function should //not capture a variable with non-automatic //storage //send heartbeat request to all workers: workers reply to such request //with a 'ready' message std::for_each(workers.begin(), workers.end(), [backend, hb](const worker_info& wi) { const int id = wi.id(); zmq_send(backend, &id, sizeof(id), ZMQ_SNDMORE); zmq_send(backend, 0, 0, ZMQ_SNDMORE); zmq_send(backend, &hb, sizeof(hb), 0); }); } zmq_close(frontend); zmq_close(backend); zmq_ctx_destroy(context); return 0; }