Created
November 15, 2014 10:45
-
-
Save hintjens/795ddedd577e3e0f00fc to your computer and use it in GitHub Desktop.
test timers & tickets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Shows relative performance of zloop timers vs tickets | |
The problem is when you have large numbers of DEALER clients talking | |
to a ROUTER server, and the server wants to expire idle clients with | |
some timeout, e.g. 30 seconds. Using zloop timers, this means deleting | |
and then recreating a timer for each received message. zloop does not | |
order its timers, and even if it did, finding a timer means searching | |
the list, an O(N) cost. | |
There are additional problems with the timer design of zloop, e.g. | |
zloop scans all timers each time it does a poll, which is potentially | |
for each recv operation. I may look at that later. For now my focus is | |
managing large sets of expiry timers. | |
There are various possible solutions to this problem, which get rather | |
complex. We can keep things simple by observing that a server typically | |
uses the same expiry period for all clients. Thus, our basic data | |
structure is an ordered list of clients or timers. The oldest client | |
or timer is at the list head, the youngest at the tail. Each time we | |
have a message from a client we take it out of the list and move it to | |
the tail. | |
To support this, zxlist works with node "handles" which let us move nodes | |
without searching the list. | |
zloop implements this as "tickets", which are expiry timers where a new | |
ticket always expires after the last ticket held so far, if any. The | |
existing zloop timers are then used for low-volume timers, and zloop | |
lets you enforce this with a zloop_set_timer_max () method. | |
This test case shows the relative difference in performance: | |
Testing zloop_timer insert/reset (1M simulated messages) | |
125 clients => 488 msecs | |
250 clients => 792 msecs | |
500 clients => 1505 msecs | |
1000 clients => 3690 msecs | |
2000 clients => 7853 msecs | |
Testing zloop_ticket insert/reset (1M simulated messages) | |
125 clients => 43 msecs | |
250 clients => 44 msecs | |
500 clients => 47 msecs | |
1000 clients => 50 msecs | |
2000 clients => 56 msecs | |
*/ | |
#include <czmq.h> | |
static int | |
s_handle_timer (zloop_t *loop, int timer_id, void *arg) | |
{ | |
return 0; | |
} | |
int main (void) | |
{ | |
int nbr_messages = 1000000; | |
printf ("Testing zloop_timer insert/reset (1M simulated messages)\n"); | |
int nbr_clients = 125; | |
while (nbr_clients < 4000) { | |
zloop_t *loop = zloop_new (); | |
int timer_id [nbr_clients]; | |
int client_nbr; | |
for (client_nbr = 0; client_nbr < nbr_clients; client_nbr++) | |
timer_id [client_nbr] = zloop_timer (loop, 30000, 1, s_handle_timer, NULL); | |
int64_t start = zclock_time (); | |
int message_nbr; | |
for (message_nbr = 0; message_nbr < nbr_messages; message_nbr++) { | |
client_nbr = randof (nbr_clients); | |
zloop_timer_end (loop, timer_id [client_nbr]); | |
timer_id [client_nbr] = zloop_timer (loop, 30000, 1, s_handle_timer, NULL); | |
} | |
zloop_destroy (&loop); | |
printf ("%d clients => %d msecs\n\n", nbr_clients, (int) (zclock_time () - start)); | |
nbr_clients *= 2; | |
} | |
nbr_clients = 125; | |
printf ("Testing zloop_ticket insert/reset (1M simulated messages)\n"); | |
while (nbr_clients < 4000) { | |
zloop_t *loop = zloop_new (); | |
zloop_set_ticket_delay (loop, 30000); | |
void *handle [nbr_clients]; | |
int client_nbr; | |
for (client_nbr = 0; client_nbr < nbr_clients; client_nbr++) | |
handle [client_nbr] = zloop_ticket (loop, s_handle_timer, NULL); | |
int64_t start = zclock_time (); | |
int message_nbr; | |
for (message_nbr = 0; message_nbr < nbr_messages; message_nbr++) { | |
client_nbr = randof (nbr_clients); | |
zloop_ticket_reset (loop, handle [client_nbr]); | |
} | |
printf ("%d clients => %d msecs\n", nbr_clients, (int) (zclock_time () - start)); | |
zloop_destroy (&loop); | |
nbr_clients *= 2; | |
} | |
exit (0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment