From 290fb53feea76f9749e4630ec71552e41afa59de Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Wed, 9 May 2007 03:18:16 +0000 Subject: * Added Buuyo-Tama's shortlist for send/eof sockets (defined out for now). * Replaced toupper/tolower in ladmin by TOUPPER/TOLOWER defines. Shortlist: It's a list of sockets that have data to send and/or are ready for eof processing. It aims to reduce the amount of time spent on do_sendrecv, where it was spending ~13.5% of execution time on a server with 1k users at WoE. thanks to Buuyo-tama for the profile info and code git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@10506 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/socket.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/common/socket.h | 22 +++++++++++ 2 files changed, 130 insertions(+), 3 deletions(-) (limited to 'src/common') diff --git a/src/common/socket.c b/src/common/socket.c index efc51b99d..a538f3e31 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -78,6 +78,11 @@ size_t wfifo_size = (16*1024); struct socket_data* session[FD_SETSIZE]; +#ifdef SEND_SHORTLIST +struct send_shortlist_node *send_shortlist = NULL; +fd_set send_shortlist_fd_set; +#endif + int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE @@ -148,6 +153,11 @@ void setsocketopts(int fd) *--------------------------------------*/ void set_eof(int fd) { +#ifdef SEND_SHORTLIST + // Add this socket to the shortlist for eof handling. + send_shortlist_add_fd(fd); +#endif + if (session_isActive(fd)) session[fd]->eof = 1; } @@ -495,6 +505,10 @@ int WFIFOSET(int fd, int len) // Even the inter-server buffer may need reallocating! [Skotlex] realloc_writefifo(fd, newreserve); +#ifdef SEND_SHORTLIST + send_shortlist_add_fd(fd); +#endif + return 0; } @@ -509,6 +523,9 @@ int do_sendrecv(int next) //PRESEND Need to do this to ensure that the clients get something to do //which hopefully will cause them to send packets. [Meruru] +#ifdef SEND_SHORTLIST + send_shortlist_do_sends(); +#else for (i = 1; i < fd_max; i++) { if(!session[i]) @@ -517,6 +534,7 @@ int do_sendrecv(int next) if(session[i]->wdata_size) session[i]->func_send(i); } +#endif timeout.tv_sec = next/1000; timeout.tv_usec = next%1000*1000; @@ -549,7 +567,7 @@ int do_sendrecv(int next) { ShowError("Deleting invalid session %d\n", i); //So the code can react accordingly - session[i]->eof = 1; + set_eof(i); session[i]->func_parse(i); delete_session(i); //free the bad session continue; @@ -579,6 +597,9 @@ int do_sendrecv(int next) } #endif +#ifdef SEND_SHORTLIST + send_shortlist_do_sends(); +#else for (i = 1; i < fd_max; i++) { if(!session[i]) @@ -592,6 +613,7 @@ int do_sendrecv(int next) session[i]->func_parse(i); //This should close the session inmediately. } } +#endif return 0; } @@ -606,7 +628,7 @@ int do_parsepacket(void) if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { ShowInfo ("Session #%d timed out\n", i); - session[i]->eof = 1; + set_eof(i); } session[i]->func_parse(i); @@ -616,7 +638,7 @@ int do_parsepacket(void) /* after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) */ if (session[i]->rdata_size == rfifo_size && session[i]->max_rdata == rfifo_size) { - session[i]->eof = 1; + set_eof(i); continue; } RFIFOFLUSH(i); @@ -1134,3 +1156,86 @@ uint16 ntows(uint16 neshort) { return ((neshort & 0xFF) << 8) | ((neshort & 0xFF00) >> 8); } + +#ifdef SEND_SHORTLIST +// Add a fd to the shortlist so that it'll be recognized as a fd that needs +// sending (or eof handling) done on it. +void send_shortlist_add_fd(int fd) +{ + struct send_shortlist_node* new_node; + + if (FD_ISSET(fd, &send_shortlist_fd_set)) + // Refuse to add duplicate FDs to the shortlist + return; + + new_node = aMalloc(sizeof(*new_node)); + + FD_SET(fd, &send_shortlist_fd_set); + + // Add the new node to the beginning of the shortlist linked list. + new_node->fd = fd; + new_node->prev = NULL; + new_node->next = send_shortlist; + if (new_node->next) + new_node->next->prev = new_node; + + send_shortlist = new_node; +} + +// Do pending network sends (and eof handling) from the shortlist. +void send_shortlist_do_sends() +{ + struct send_shortlist_node + *current_node = send_shortlist, + *next_node; + + while (current_node) + { + int delete_current_node = 1; + + next_node = current_node->next; + + // If this session still exists, perform send operations on it and + // check for the eof state. + if (session[ current_node->fd ]) + { + if (session[ current_node->fd ]->wdata_size) + session[ current_node->fd ]->func_send( current_node->fd ); + + // If it's been marked as eof, call the parse func on it so that + // the socket will be immediately closed. + if (session[ current_node->fd ]->eof) + session[ current_node->fd ]->func_parse( current_node->fd ); + + // If the session still exists, is not eof and has things left to + // be sent from it we'll keep it in the send shortlist. + if (session[ current_node->fd ] && + !session[ current_node->fd ]->eof && + session[ current_node->fd ]->wdata_size) + delete_current_node = 0; + } + + // If this session has been marked for removal from the short list, + // we'll proceed in doing this. + if (delete_current_node) + { + FD_CLR(current_node->fd, &send_shortlist_fd_set); + + // Remove its link entry + if (!current_node->prev) + send_shortlist = next_node; + else + current_node->prev->next = next_node; + + if (current_node->next) + current_node->next->prev = current_node->prev; + + // and free its memory + aFree(current_node); + } + + // Iterate to the next node (session) in the short list + current_node = next_node; + } +} +#endif diff --git a/src/common/socket.h b/src/common/socket.h index 3d860e166..a040772a9 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -140,4 +140,26 @@ int socket_getips(uint32* ips, int max); extern uint32 addr_[16]; // ip addresses of local host (host byte order) extern int naddr_; // # of ip addresses +void set_eof(int fd); + +/// Use a shortlist of sockets instead of iterating all sessions for sockets +/// that have data to send or need eof processing. +/// +/// @author Buuyo-tama +//#define SEND_SHORTLIST + +#ifdef SEND_SHORTLIST +struct send_shortlist_node { + struct send_shortlist_node *next; // Next node in the linked list + struct send_shortlist_node *prev; // Previous node in the linked list + int fd; // FD that needs sending. +}; + +// Add a fd to the shortlist so that it'll be recognized as a fd that needs +// sending done on it. +void send_shortlist_add_fd(int fd); +// Do pending network sends (and eof handling) from the shortlist. +void send_shortlist_do_sends(); +#endif + #endif /* _SOCKET_H_ */ -- cgit v1.2.3-70-g09d2