nsprpub/pr/tests/thruput.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7 ** File:        thruput.c
     8 ** Description: Test server's throughput capability comparing various
     9 **              implmentation strategies.
    10 **
    11 ** Note:        Requires a server machine and an aribitrary number of
    12 **              clients to bang on it. Trust the numbers on the server
    13 **              more than those being displayed by the various clients.
    14 */
    16 #include "prerror.h"
    17 #include "prinrval.h"
    18 #include "prinit.h"
    19 #include "prio.h"
    20 #include "prlock.h"
    21 #include "prmem.h"
    22 #include "prnetdb.h"
    23 #include "prprf.h"
    24 #include "prthread.h"
    25 #include "pprio.h"
    26 #include "plerror.h"
    27 #include "plgetopt.h"
    29 #define ADDR_BUFFER 100
    30 #define PORT_NUMBER 51877
    31 #define SAMPLING_INTERVAL 10
    32 #define BUFFER_SIZE (32 * 1024)
    34 static PRInt32 domain = PR_AF_INET;
    35 static PRInt32 protocol = 6;  /* TCP */
    36 static PRFileDesc *err = NULL;
    37 static PRIntn concurrency = 1;
    38 static PRInt32 xport_buffer = -1;
    39 static PRUint32 initial_streams = 1;
    40 static PRInt32 buffer_size = BUFFER_SIZE;
    41 static PRThreadScope thread_scope = PR_LOCAL_THREAD;
    43 typedef struct Shared
    44 {
    45     PRLock *ml;
    46     PRUint32 sampled;
    47     PRUint32 threads;
    48     PRIntervalTime timein;
    49     PRNetAddr server_address;
    50 } Shared;
    52 static Shared *shared = NULL;
    54 static PRStatus PrintAddress(const PRNetAddr* address)
    55 {
    56     char buffer[ADDR_BUFFER];
    57     PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
    58     if (PR_SUCCESS == rv)
    59         PR_fprintf(err, "%s:%u\n", buffer, PR_ntohs(address->inet.port));
    60     else PL_FPrintError(err, "PR_NetAddrToString");
    61     return rv;
    62 }  /* PrintAddress */
    65 static void PR_CALLBACK Clientel(void *arg)
    66 {
    67     PRStatus rv;
    68     PRFileDesc *xport;
    69     PRInt32 bytes, sampled;
    70     PRIntervalTime now, interval;
    71     PRBool do_display = PR_FALSE;
    72     Shared *shared = (Shared*)arg;
    73     char *buffer = (char*)PR_Malloc(buffer_size);
    74     PRNetAddr *server_address = &shared->server_address;
    75     PRIntervalTime connect_timeout = PR_SecondsToInterval(5);
    76     PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
    78     PR_fprintf(err, "Client connecting to ");
    79     (void)PrintAddress(server_address);
    81     do
    82     {
    83         xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
    84         if (NULL == xport)
    85         {
    86             PL_FPrintError(err, "PR_Socket");
    87             return;
    88         }
    90         if (xport_buffer != -1)
    91         {
    92             PRSocketOptionData data;
    93             data.option = PR_SockOpt_RecvBufferSize;
    94             data.value.recv_buffer_size = (PRSize)xport_buffer;
    95             rv = PR_SetSocketOption(xport, &data);
    96             if (PR_FAILURE == rv)
    97                 PL_FPrintError(err, "PR_SetSocketOption - ignored");
    98             data.option = PR_SockOpt_SendBufferSize;
    99             data.value.send_buffer_size = (PRSize)xport_buffer;
   100             rv = PR_SetSocketOption(xport, &data);
   101             if (PR_FAILURE == rv)
   102                 PL_FPrintError(err, "PR_SetSocketOption - ignored");
   103         }
   105         rv = PR_Connect(xport, server_address, connect_timeout);
   106         if (PR_FAILURE == rv)
   107         {
   108             PL_FPrintError(err, "PR_Connect");
   109             if (PR_IO_TIMEOUT_ERROR != PR_GetError())
   110                 PR_Sleep(connect_timeout);
   111             PR_Close(xport);  /* delete it and start over */
   112         }
   113     } while (PR_FAILURE == rv);
   115     do
   116     {
   117         bytes = PR_Recv(
   118             xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
   119         PR_Lock(shared->ml);
   120         now = PR_IntervalNow();
   121         shared->sampled += bytes;
   122         interval = now - shared->timein;
   123         if (interval > sampling_interval)
   124         {
   125             sampled = shared->sampled;
   126             shared->timein = now;
   127             shared->sampled = 0;
   128             do_display = PR_TRUE;
   129         }
   130         PR_Unlock(shared->ml);
   132         if (do_display)
   133         {
   134             PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
   135             PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
   136             do_display = PR_FALSE;
   137         }
   139     } while (bytes > 0);
   140 }  /* Clientel */
   142 static void Client(const char *server_name)
   143 {
   144     PRStatus rv;
   145     PRHostEnt host;
   146     char buffer[PR_NETDB_BUF_SIZE];
   147     PRIntervalTime dally = PR_SecondsToInterval(60);
   148     PR_fprintf(err, "Translating the name %s\n", server_name);
   149     rv = PR_GetHostByName(server_name, buffer, sizeof(buffer), &host);
   150     if (PR_FAILURE == rv)
   151         PL_FPrintError(err, "PR_GetHostByName");
   152     else
   153     {
   154         if (PR_EnumerateHostEnt(
   155             0, &host, PORT_NUMBER, &shared->server_address) < 0)
   156             PL_FPrintError(err, "PR_EnumerateHostEnt");
   157         else
   158         {
   159             do
   160             {
   161                 shared->threads += 1;
   162                 (void)PR_CreateThread(
   163                     PR_USER_THREAD, Clientel, shared,
   164                     PR_PRIORITY_NORMAL, thread_scope,
   165                     PR_UNJOINABLE_THREAD, 8 * 1024);
   166                 if (shared->threads == initial_streams)
   167                 {
   168                     PR_Sleep(dally);
   169                     initial_streams += 1;
   170                 }
   171             } while (PR_TRUE);
   172         }
   173     }
   174 }
   176 static void PR_CALLBACK Servette(void *arg)
   177 {
   178     PRInt32 bytes, sampled;
   179     PRIntervalTime now, interval;
   180     PRBool do_display = PR_FALSE;
   181     PRFileDesc *client = (PRFileDesc*)arg;
   182     char *buffer = (char*)PR_Malloc(buffer_size);
   183     PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL);
   185     if (xport_buffer != -1)
   186     {
   187         PRStatus rv;
   188         PRSocketOptionData data;
   189         data.option = PR_SockOpt_RecvBufferSize;
   190         data.value.recv_buffer_size = (PRSize)xport_buffer;
   191         rv = PR_SetSocketOption(client, &data);
   192         if (PR_FAILURE == rv)
   193             PL_FPrintError(err, "PR_SetSocketOption - ignored");
   194         data.option = PR_SockOpt_SendBufferSize;
   195         data.value.send_buffer_size = (PRSize)xport_buffer;
   196         rv = PR_SetSocketOption(client, &data);
   197         if (PR_FAILURE == rv)
   198             PL_FPrintError(err, "PR_SetSocketOption - ignored");
   199     }
   201     do
   202     {
   203         bytes = PR_Send(
   204             client, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT);
   206         PR_Lock(shared->ml);
   207         now = PR_IntervalNow();
   208         shared->sampled += bytes;
   209         interval = now - shared->timein;
   210         if (interval > sampling_interval)
   211         {
   212             sampled = shared->sampled;
   213             shared->timein = now;
   214             shared->sampled = 0;
   215             do_display = PR_TRUE;
   216         }
   217         PR_Unlock(shared->ml);
   219         if (do_display)
   220         {
   221             PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval);
   222             PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate);
   223             do_display = PR_FALSE;
   224         }
   225     } while (bytes > 0);
   226 }  /* Servette */
   228 static void Server(void)
   229 {
   230     PRStatus rv;
   231     PRNetAddr server_address, client_address;
   232     PRFileDesc *xport = PR_Socket(domain, PR_SOCK_STREAM, protocol);
   234     if (NULL == xport)
   235     {
   236         PL_FPrintError(err, "PR_Socket");
   237         return;
   238     }
   240     rv = PR_InitializeNetAddr(PR_IpAddrAny, PORT_NUMBER, &server_address);
   241     if (PR_FAILURE == rv) PL_FPrintError(err, "PR_InitializeNetAddr");
   242     else
   243     {
   244         rv = PR_Bind(xport, &server_address);
   245         if (PR_FAILURE == rv) PL_FPrintError(err, "PR_Bind");
   246         else
   247         {
   248             PRFileDesc *client;
   249             rv = PR_Listen(xport, 10);
   250             PR_fprintf(err, "Server listening on ");
   251             (void)PrintAddress(&server_address);
   252             do
   253             {
   254                 client = PR_Accept(
   255                     xport, &client_address, PR_INTERVAL_NO_TIMEOUT);
   256                 if (NULL == client) PL_FPrintError(err, "PR_Accept");
   257                 else
   258                 {
   259                     PR_fprintf(err, "Server accepting from ");
   260                     (void)PrintAddress(&client_address);
   261                     shared->threads += 1;
   262                     (void)PR_CreateThread(
   263                         PR_USER_THREAD, Servette, client,
   264                         PR_PRIORITY_NORMAL, thread_scope,
   265                         PR_UNJOINABLE_THREAD, 8 * 1024);
   266                 }
   267             } while (PR_TRUE);
   269         }
   270     }
   271 }  /* Server */
   273 static void Help(void)
   274 {
   275     PR_fprintf(err, "Usage: [-h] [<server>]\n");
   276     PR_fprintf(err, "\t-s <n>   Initial # of connections        (default: 1)\n");
   277     PR_fprintf(err, "\t-C <n>   Set 'concurrency'               (default: 1)\n");
   278     PR_fprintf(err, "\t-b <nK>  Client buffer size              (default: 32k)\n");
   279     PR_fprintf(err, "\t-B <nK>  Transport recv/send buffer size (default: sys)\n");
   280     PR_fprintf(err, "\t-G       Use GLOBAL threads              (default: LOCAL)\n");
   281     PR_fprintf(err, "\t-X       Use XTP transport               (default: TCP)\n");
   282     PR_fprintf(err, "\t-6       Use IPv6                        (default: IPv4)\n");
   283     PR_fprintf(err, "\t-h       This message and nothing else\n");
   284     PR_fprintf(err, "\t<server> DNS name of server\n");
   285     PR_fprintf(err, "\t\tIf <server> is not specified, this host will be\n");
   286     PR_fprintf(err, "\t\tthe server and not act as a client.\n");
   287 }  /* Help */
   289 int main(int argc, char **argv)
   290 {
   291     PLOptStatus os;
   292     const char *server_name = NULL;
   293     PLOptState *opt = PL_CreateOptState(argc, argv, "hGX6C:b:s:B:");
   295     err = PR_GetSpecialFD(PR_StandardError);
   297     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   298     {
   299         if (PL_OPT_BAD == os) continue;
   300         switch (opt->option)
   301         {
   302         case 0:  /* Name of server */
   303             server_name = opt->value;
   304             break;
   305         case 'G':  /* Globular threads */
   306             thread_scope = PR_GLOBAL_THREAD;
   307             break;
   308         case 'X':  /* Use XTP as the transport */
   309             protocol = 36;
   310             break;
   311         case '6':  /* Use IPv6 */
   312             domain = PR_AF_INET6;
   313             break;
   314         case 's':  /* initial_streams */
   315             initial_streams = atoi(opt->value);
   316             break;
   317         case 'C':  /* concurrency */
   318             concurrency = atoi(opt->value);
   319             break;
   320         case 'b':  /* buffer size */
   321             buffer_size = 1024 * atoi(opt->value);
   322             break;
   323         case 'B':  /* buffer size */
   324             xport_buffer = 1024 * atoi(opt->value);
   325             break;
   326         case 'h':  /* user wants some guidance */
   327         default:
   328             Help();  /* so give him an earful */
   329             return 2;  /* but not a lot else */
   330         }
   331     }
   332     PL_DestroyOptState(opt);
   334     shared = PR_NEWZAP(Shared);
   335     shared->ml = PR_NewLock();
   337     PR_fprintf(err,
   338         "This machine is %s\n",
   339         (NULL == server_name) ? "the SERVER" : "a CLIENT");
   341     PR_fprintf(err,
   342         "Transport being used is %s\n",
   343         (6 == protocol) ? "TCP" : "XTP");
   345     if (PR_GLOBAL_THREAD == thread_scope)
   346     {
   347         if (1 != concurrency)
   348         {
   349             PR_fprintf(err, "  **Concurrency > 1 and GLOBAL threads!?!?\n");
   350             PR_fprintf(err, "  **Ignoring concurrency\n");
   351             concurrency = 1;
   352         }
   353     }
   355     if (1 != concurrency)
   356     {
   357         PR_SetConcurrency(concurrency);
   358         PR_fprintf(err, "Concurrency set to %u\n", concurrency);
   359     }
   361     PR_fprintf(err,
   362         "All threads will be %s\n",
   363         (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
   365     PR_fprintf(err, "Client buffer size will be %u\n", buffer_size);
   367     if (-1 != xport_buffer)
   368     PR_fprintf(
   369         err, "Transport send & receive buffer size will be %u\n", xport_buffer);
   372     if (NULL == server_name) Server();
   373     else Client(server_name);
   375     return 0;
   376 }  /* main */
   378 /* thruput.c */

mercurial