home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / thruput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  12.6 KB  |  399 lines

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