botsense  3.2.0
RoadNarrows Client-Server Proxied Services Framework
bsLoadTest.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: BotSense
4 //
5 // Program: bsLoadTest
6 //
7 // File: bsLoadTest.c
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2010-09-13 10:25:05 -0600 (Mon, 13 Sep 2010) $
12  * $Rev: 581 $
13  *
14  * \brief BotSense bsProxy server load tester client(s).
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2010-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 // Permission is hereby granted, without written agreement and without
24 // license or royalty fees, to use, copy, modify, and distribute this
25 // software and its documentation for any purpose, provided that
26 // (1) The above copyright notice and the following two paragraphs
27 // appear in all copies of the source code and (2) redistributions
28 // including binaries reproduces these notices in the supporting
29 // documentation. Substantial modifications to this software may be
30 // copyrighted by their authors and need not follow the licensing terms
31 // described here, provided that the new terms are clearly indicated in
32 // all files where they apply.
33 //
34 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
35 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
36 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
37 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
38 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
39 // THE POSSIBILITY OF SUCH DAMAGE.
40 //
41 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
42 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
43 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
44 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
45 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
46 //
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #include <sys/time.h>
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <libgen.h>
54 #include <pthread.h>
55 #include <time.h>
56 #include <string.h>
57 #include <errno.h>
58 
59 #include "rnr/rnrconfig.h"
60 #include "rnr/new.h"
61 #include "rnr/opts.h"
62 #include "rnr/log.h"
63 
64 #include "botsense/BotSense.h"
65 #include "botsense/libBotSense.h"
66 #include "botsense/bsProxyMsgs.h"
67 
68 #include "botsense/bsI2C.h"
69 #include "botsense/bsI2CMsgs.h"
70 #include "botsense/bsNull.h"
71 #include "botsense/bsNullMsgs.h"
72 #include "botsense/bsSerial.h"
73 #include "botsense/bsSerialMsgs.h"
74 
75 #include "version.h"
76 
77 
78 // ---------------------------------------------------------------------------
79 // Private Interface
80 // ---------------------------------------------------------------------------
81 
82 //
83 // Application Exit Codes
84 //
85 #define APP_EC_OK 0 ///< success exit code
86 #define APP_EC_USAGE 2 ///< usage error exit code
87 #define APP_EC_EXEC 4 ///< execution error exit code
88 
89 #define LT_MAX_CLIENTS 256 ///< maximum number of load testing clients
90 #define LT_MAX_VCONN 4 ///< maximum number of virtual conn. / client
91 #define LT_N_CLIENT_DFT 1 ///< default option load testing client count
92 
93 #define LT_DEVICES_DFT "server,null"
94  ///< default option list of proxied devices
95 #define LT_DEV_SERVER 0x0001 ///< load test server-terminated requests
96 #define LT_DEV_I2C 0x0002 ///< load test proxied \h_i2c device requests
97 #define LT_DEV_NULL 0x0004 ///< load test proxied /dev/null requests
98 #define LT_DEV_SERIAL 0x0008 ///< load test proxied serial device requests
99 
100 #define LT_T_MIN 1000 ///< minimum thread sleep time
101 #define LT_T_MAX 2000000 ///< minimum thread sleep time
102 
103 //
104 // The command and command-line options.
105 //
106 static char *Argv0; ///< this command basename
107 static char *OptsProxyServer = "localhost"; ///< proxy server addr/port
108 static int OptsClientCnt = LT_N_CLIENT_DFT; ///< number of clients
109 static char *OptsDevices = LT_DEVICES_DFT; ///< number of clients
110 static bool_t OptsFixedDiag = false; ///< fixed diagnostics
111 static char *OptsDevSerial = "/dev/ttyS0"; ///< serial device
112 static char *OptsDevI2C = "/dev/i2c-0"; ///< i2c device
113 
114 //
115 // Forward declarations.
116 //
117 static int OptsCvtArgServerAddr(const char *argv0, const char *sOptName,
118  char *optarg, void *pOptVal);
119 static int OptsCvtArgClientCnt(const char *argv0, const char *sOptName,
120  char *optarg, void *pOptVal);
121 static int OptsCvtArgDevices(const char *argv0, const char *sOptName,
122  char *optarg, void *pOptVal);
123 
124 /*!
125  * \brief Program information.
126  */
127 static OptsPgmInfo_T PgmInfo =
128 {
129  .synopsis =
130  "BotSense bsProxy server load tester client.",
131 
132  .long_desc =
133  "The %P application creates a multi-client, multi-thread application to "
134  "load test both the bsProxy server and the libbotsense client library."
135 };
136 
137 /*!
138  * \brief Command-line options information.
139  */
140 static OptsInfo_T OptsInfo[] =
141 {
142  // -p, --proxy=<addr[:port]>
143  {
144  .long_opt = "proxy",
145  .short_opt = 'p',
146  .has_arg = required_argument,
147  .has_default= true,
148  .opt_addr = &OptsProxyServer,
149  .fn_cvt = OptsCvtArgServerAddr,
150  .fn_fmt = OptsFmtStr,
151  .arg_name = "<addr[:port]>",
152  .opt_desc = "Proxy Server's network address. The format of the address "
153  "can be either a network hostname or a dotted IP address "
154  "number. If port is not specfied, then the default port "
155  "9195 is used."
156  },
157 
158  // -c, --count=<count>
159  {
160  .long_opt = "count",
161  .short_opt = 'c',
162  .has_arg = required_argument,
163  .has_default= true,
164  .opt_addr = &OptsClientCnt,
165  .fn_cvt = OptsCvtArgClientCnt,
166  .fn_fmt = OptsFmtInt,
167  .arg_name = "<count>",
168  .opt_desc = "Number of client's to create and run."
169  },
170 
171  // --devices=<list>
172  {
173  .long_opt = "devices",
174  .short_opt = OPTS_NO_SHORT,
175  .has_arg = required_argument,
176  .has_default= true,
177  .opt_addr = &OptsDevices,
178  .fn_cvt = OptsCvtArgDevices,
179  .fn_fmt = OptsFmtStr,
180  .arg_name = "<list>",
181  .opt_desc = "List of proxied devices where each client will create "
182  "a thread and load test. Format:\n"
183  " list: dev[,dev...]\n"
184  " dev: server i2c null serial"
185  },
186 
187 
188  // --fixeddiag
189  {
190  .long_opt = "fixeddiag",
191  .short_opt = OPTS_NO_SHORT,
192  .has_arg = no_argument,
193  .has_default= true,
194  .opt_addr = &OptsFixedDiag,
195  .fn_cvt = OptsCvtArgBool,
196  .fn_fmt = OptsFmtBool,
197  .arg_name = NULL,
198  .opt_desc = "Fix message tracing and logging diagnostics to the values "
199  "set when %P was invoked."
200  },
201 
202  // --serdev=<dev>
203  {
204  .long_opt = "serdev",
205  .short_opt = OPTS_NO_SHORT,
206  .has_arg = required_argument,
207  .has_default= true,
208  .opt_addr = &OptsDevSerial,
209  .fn_cvt = OptsCvtArgStr,
210  .fn_fmt = OptsFmtStr,
211  .arg_name = "<dev>",
212  .opt_desc = "Proxied serial device. The interface module is fixed at "
213  "libbserver_serial."
214  },
215 
216  // --i2cdev=<dev>
217  {
218  .long_opt = "i2cdev",
219  .short_opt = OPTS_NO_SHORT,
220  .has_arg = required_argument,
221  .has_default= true,
222  .opt_addr = &OptsDevI2C,
223  .fn_cvt = OptsCvtArgStr,
224  .fn_fmt = OptsFmtStr,
225  .arg_name = "<dev>",
226  .opt_desc = "Proxied I2C device. The interface module is fixed at "
227  "libbserver_i2c."
228  },
229 
230  {NULL, }
231 };
232 
233 //
234 // State
235 //
236 static char *ProxyIPAddr = "localhost"; ///< default bsProxy IP addr
238  ///< default bsProxy port
239 static BsClient_P Client[LT_MAX_CLIENTS]; ///< array of clients
240 static uint_t ProxiedDevices = LT_DEV_SERVER |
241  LT_DEV_NULL; ///< proxied devices
242 static union
243 {
244  ulong_t seed; ///< the initial seed
245  ushort_t xsubi[3]; ///< successive x_i'th 48-bit value
246 } RandomSeq; ///< Random seed
247 
248 
249 // ...........................................................................
250 // Execution Functions
251 // ...........................................................................
252 
253 /*!
254  * \brief Seed random number generator.
255  */
256 static void RandSeed()
257 {
258  RandomSeq.seed = (ulong_t)time(NULL);
259  srand48((long)RandomSeq.seed);
260 }
261 
262 /*!
263  * \brief Generate random integer between [0,n).
264  *
265  * \param n Upper value.
266  *
267  * \return Random unsigned integer.
268  */
269 static uint_t RandN(uint_t n)
270 {
271  double r;
272 
273  r = erand48( RandomSeq.xsubi );
274 
275  return (uint_t)(n * r);
276 }
277 
278 /*!
279  * \brief Sleep for a random \h_usec duration between [tmin, tmax].
280  *
281  * \param tmin Minimum sleep value.
282  * \param tmax Maximum sleep value.
283  */
284 static void RandSleep(uint_t tmin, uint_t tmax)
285 {
286  usleep( tmin + RandN(tmax-tmin) );
287 }
288 
289 /*!
290  * \brief Randomly pick a virtual connection in list.
291  *
292  * \param pVConnList Virtual connection list.
293  *
294  * \return Virtual connection handle.
295  */
297 {
298  if( pVConnList->m_uCount == 0 )
299  {
301  }
302  else
303  {
304  return pVConnList->m_vecHnd[RandN((uint_t)pVConnList->m_uCount)];
305  }
306 }
307 
308 /*!
309  * \brief Load test proxied \h_i2c device thread.
310  *
311  * \param pArg BotSense client (casted as a NULL).
312  *
313  * \return Returns NULL on thread exit.
314  */
315 static void *LtThreadI2C(void *pArg)
316 {
317  enum ActionOps
318  {
319  ActionScan = BsI2CMsgIdReqScan,
320  ActionOpenClose = BsI2CMsgIdNumOf
321  };
322 
323  static uint_t actions[] =
324  {
325  ActionOpenClose, ActionScan
326  };
327 
328  static uint_t uNumActions = (uint_t)arraysize(actions);
329 
330  BsClient_P pClient = (BsClient_P)pArg;
331  const char *sClientName = bsClientAttrGetName(pClient);
332  uint_t uCloseFreq = 50;
333  BsVConnHnd_T hndVConn;
334  bool_t bIsOpen;
335  i2c_addr_t addrs[256];
336  uint_t i;
337  int rc;
338 
339  // open proxied device
340  hndVConn = bsI2CReqOpen(pClient, OptsDevI2C, false);
341 
342  if( hndVConn < 0 )
343  {
344  BSCLIENT_LOG_ERROR(pClient, hndVConn, "%s", OptsDevI2C);
345  return NULL;
346  }
347 
348  printf("<%s>: i2copen: %s\n", sClientName, OptsDevI2C);
349 
350  bIsOpen = true;
351 
352  printf("<%s>: i2c load test thread started.\n", sClientName);
353 
354  while( true )
355  {
356  // randomly sleep between minimum and maximum times
358 
359  // choose random request to send
360  switch( actions[RandN(uNumActions)] )
361  {
362  case ActionOpenClose:
363  if( bIsOpen )
364  {
365  if( RandN(uCloseFreq) == 0 )
366  {
367  rc = bsI2CReqClose(pClient, hndVConn);
368  if( rc == BS_OK )
369  {
370  printf("<%s>: i2cclose: %s\n", sClientName, OptsDevI2C);
371  bIsOpen = false;
372  }
373  else
374  {
375  printf("<%s>: i2cclose: failed: rc=%d\n", sClientName, rc);
376  }
377  }
378  }
379  else
380  {
381  // open proxied device
382  hndVConn = bsI2CReqOpen(pClient, OptsDevI2C, false);
383 
384  if( hndVConn >= 0 )
385  {
386  printf("<%s>: i2copen: %s\n", sClientName, OptsDevI2C);
387  bIsOpen = true;
388  }
389  else
390  {
391  printf("<%s>: i2copen: failed: rc=%d\n", sClientName, hndVConn);
392  }
393  }
394  break;
395  case ActionScan:
396  if( bIsOpen )
397  {
398  rc = bsI2CReqScan(pClient, hndVConn, addrs, arraysize(addrs));
399  if( rc > 0 )
400  {
401  printf("<%s>: i2cscan: %d addresses:", sClientName, rc);
402  for(i=0; i<rc; ++i)
403  {
404  printf(" 0x%02x", addrs[i]);
405  }
406  printf(".\n");
407  }
408  else
409  {
410  printf("<%s>: i2cscan: failed: rc=%d\n", sClientName, rc);
411  }
412  }
413  break;
414  default:
415  break;
416  }
417  }
418 
419  printf("<%s>: i2c load test thread terminated.\n", sClientName);
420 
421  return NULL;
422 }
423 
424 /*!
425  * \brief Start proxied \h_i2c device load test thread.
426  *
427  * \param pClient BotSense client.
428  */
430 {
431  pthread_t thread;
432 
433  if( pthread_create(&thread, NULL, LtThreadI2C, (void *)pClient) )
434  {
436  "pthread_create(\"/dev/null\")");
437  return;
438  }
439 }
440 
441 /*!
442  * \brief Load test proxied /dev/null device thread.
443  *
444  * \param pArg BotSense client (casted as a NULL).
445  *
446  * \return Returns NULL on thread exit.
447  */
448 static void *LtThreadNull(void *pArg)
449 {
450  enum ActionOps
451  {
452  ActionWrite = BsNullMsgIdReqWrite,
453  ActionOpenClose = BsNullMsgIdNumOf
454  };
455 
456  static uint_t actions[] =
457  {
458  ActionOpenClose, ActionWrite
459  };
460 
461  static uint_t uNumActions = (uint_t)arraysize(actions);
462 
463  static char *wrPhrase[] =
464  {
465  "It just so happens that your friend here is only MOSTLY dead.",
466  "Rest well and dream of large women.",
467  "Hello. My name is Inigo Montoya. You killed my father. Prepare to die."
468  };
469  static uint_t uNumWrPhrases = (uint_t)arraysize(wrPhrase);
470 
471  BsClient_P pClient = (BsClient_P)pArg;
472  const char *sClientName = bsClientAttrGetName(pClient);
473  uint_t uCloseFreq = 50;
474  BsVConnHnd_T hndVConn;
475  bool_t bIsOpen;
476  byte_t buf[1024];
477  uint_t i;
478  int rc;
479 
480  // open proxied device
481  hndVConn = bsNullReqOpen(pClient, false);
482 
483  if( hndVConn < 0 )
484  {
485  BSCLIENT_LOG_ERROR(pClient, hndVConn, "%s", BS_NULL_DEV_NAME);
486  return NULL;
487  }
488 
489  printf("<%s>: nullopen: %s\n", sClientName, BS_NULL_DEV_NAME);
490 
491  bIsOpen = true;
492 
493  printf("<%s>: devnull load test thread started.\n", sClientName);
494 
495  while( true )
496  {
497  // randomly sleep between minimum and maximum times
499 
500  // choose random request to send
501  switch( actions[RandN(uNumActions)] )
502  {
503  case ActionOpenClose:
504  if( bIsOpen )
505  {
506  if( RandN(uCloseFreq) == 0 )
507  {
508  rc = bsNullReqClose(pClient, hndVConn);
509  if( rc == BS_OK )
510  {
511  printf("<%s>: nullclose: %s\n", sClientName, BS_NULL_DEV_NAME);
512  bIsOpen = false;
513  }
514  else
515  {
516  printf("<%s>: nullclose: failed: rc=%d\n", sClientName, rc);
517  }
518  }
519  }
520  else
521  {
522  // open proxied device
523  hndVConn = bsNullReqOpen(pClient, false);
524 
525  if( hndVConn >= 0 )
526  {
527  printf("<%s>: nullopen: %s\n", sClientName, BS_NULL_DEV_NAME);
528  bIsOpen = true;
529  }
530  else
531  {
532  printf("<%s>: nullopen: failed: rc=%d\n", sClientName, hndVConn);
533  }
534  }
535  break;
536  case ActionWrite:
537  if( bIsOpen )
538  {
539  i = RandN(uNumWrPhrases);
540  memcpy(buf, wrPhrase[i], strlen(wrPhrase[i]));
541  rc = bsNullReqWrite(pClient, hndVConn, buf, strlen(wrPhrase[i]));
542  if( rc > 0 )
543  {
544  printf("<%s>: nullwrite: %d bytes: \"%*s\"\n",
545  sClientName, rc, rc, wrPhrase[i]);
546  }
547  else
548  {
549  printf("<%s>: nullwrite: failed: rc=%d\n", sClientName, rc);
550  }
551  }
552  break;
553  default:
554  break;
555  }
556  }
557 
558  printf("<%s>: devnull load test thread terminated.\n", sClientName);
559 
560  return NULL;
561 }
562 
563 /*!
564  * \brief Start proxied /dev/null device load test thread.
565  *
566  * \param pClient BotSense client.
567  */
569 {
570  pthread_t thread;
571 
572  if( pthread_create(&thread, NULL, LtThreadNull, (void *)pClient) )
573  {
575  "pthread_create(\"/dev/null\")");
576  return;
577  }
578 }
579 
580 /*!
581  * \brief Load test proxied serial device thread.
582  *
583  * \param pArg BotSense client (casted as a NULL).
584  *
585  * \return Returns NULL on thread exit.
586  */
587 static void *LtThreadSerial(void *pArg)
588 {
589  enum ActionOps
590  {
591  ActionRead = BsSerialMsgIdReqRead,
592  ActionTrans = BsSerialMsgIdReqTrans,
593  ActionWrite = BsSerialMsgIdReqWrite,
594  ActionOpenClose = BsSerialMsgIdNumOf
595  };
596 
597  static uint_t actions[] =
598  {
599  ActionOpenClose, ActionWrite
600  };
601 
602  static uint_t uNumActions = (uint_t)arraysize(actions);
603 
604  static char *wrPhrase[] =
605  {
606  "hello",
607  "eat me",
608  "This is the end / Beautiful friend / This is the end / "
609  "My only friend, the end"
610  };
611  static uint_t uNumWrPhrases = (uint_t)arraysize(wrPhrase);
612 
613  BsClient_P pClient = (BsClient_P)pArg;
614  const char *sClientName = bsClientAttrGetName(pClient);
615  uint_t uCloseFreq = 50;
616  BsVConnHnd_T hndVConn;
617  bool_t bIsOpen;
618  byte_t buf[1024];
619  uint_t i;
620  int rc;
621 
622  // open proxied device
623  hndVConn = bsSerialReqOpen(pClient, OptsDevSerial,
624  115200, 8, 'N', 1, false, false, false);
625 
626  if( hndVConn < 0 )
627  {
628  BSCLIENT_LOG_ERROR(pClient, hndVConn, "%s", OptsDevSerial);
629  return NULL;
630  }
631 
632  printf("<%s>: serialopen: %s\n", sClientName, OptsDevSerial);
633 
634  bIsOpen = true;
635 
636  printf("<%s>: serial load test thread started.\n", sClientName);
637 
638  while( true )
639  {
640  // randomly sleep between minimum and maximum times
642 
643  // choose random request to send
644  switch( actions[RandN(uNumActions)] )
645  {
646  case ActionOpenClose:
647  if( bIsOpen )
648  {
649  if( RandN(uCloseFreq) == 0 )
650  {
651  rc = bsSerialReqClose(pClient, hndVConn);
652  if( rc == BS_OK )
653  {
654  printf("<%s>: serialclose: %s\n", sClientName, OptsDevSerial);
655  bIsOpen = false;
656  }
657  else
658  {
659  printf("<%s>: serialclose: failed: rc=%d\n", sClientName, rc);
660  }
661  }
662  }
663  else
664  {
665  // open proxied device
666  hndVConn = bsSerialReqOpen(pClient, OptsDevSerial,
667  115200, 8, 'N', 1, false, false, false);
668 
669  if( hndVConn >= 0 )
670  {
671  printf("<%s>: serialopen: %s\n", sClientName, OptsDevSerial);
672  bIsOpen = true;
673  }
674  else
675  {
676  printf("<%s>: serialopen: failed: rc=%d\n", sClientName, hndVConn);
677  }
678  }
679  break;
680  case ActionWrite:
681  if( bIsOpen )
682  {
683  i = RandN(uNumWrPhrases);
684  memcpy(buf, wrPhrase[i], strlen(wrPhrase[i]));
685  rc = bsSerialReqWrite(pClient, hndVConn, buf, strlen(wrPhrase[i]));
686  if( rc > 0 )
687  {
688  printf("<%s>: serialwrite: %d bytes: \"%*s\"\n",
689  sClientName, rc, rc, wrPhrase[i]);
690  }
691  else
692  {
693  printf("<%s>: serialwrite: failed: rc=%d\n", sClientName, rc);
694  }
695  }
696  break;
697  case ActionRead:
698  case ActionTrans:
699  default:
700  break;
701  }
702  }
703 
704  printf("<%s>: serial load test thread terminated.\n", sClientName);
705 
706  return NULL;
707 }
708 
709 /*!
710  * \brief Start proxied serial device load test thread.
711  *
712  * \param pClient BotSense client.
713  */
715 {
716  pthread_t thread;
717 
718  if( pthread_create(&thread, NULL, LtThreadSerial, (void *)pClient) )
719  {
721  "pthread_create(\"serial\")");
722  return;
723  }
724 }
725 
726 /*!
727  * \brief Load test server-terminated messages thread.
728  *
729  * \param pArg BotSense client (casted as a NULL).
730  *
731  * \return Returns NULL on thread exit.
732  */
733 static void *LtThreadServer(void *pArg)
734 {
735  enum ActionOps
736  {
737  ActionLoopback = BsProxyMsgIdReqLoopback,
738  ActionSetLogging = BsProxyMsgIdReqSetLogging,
739  ActionGetVersion = BsProxyMsgIdReqGetVersion,
740  ActionMsgTrace = BsProxyMsgIdReqMsgTrace,
741  ActionGetVConnList = BsProxyMsgIdReqGetVConnList,
742  ActionGetVConnInfo = BsProxyMsgIdReqGetVConnInfo
743  };
744 
745  static uint_t actions[] =
746  {
747  ActionLoopback, ActionSetLogging, ActionGetVersion,
748  ActionMsgTrace, ActionGetVConnList, ActionGetVConnInfo
749  };
750 
751  static uint_t uNumActions = (uint_t)arraysize(actions);
752 
753  BsClient_P pClient = (BsClient_P)pArg;
754  const char *sClientName = bsClientAttrGetName(pClient);
755  BsVecHandles_T vconnlist = {0, {0, }};
756  BsVConnInfo_T vconninfo;
757  char buf[1024];
758  uint_t i, j;
759  BsVConnHnd_T hndVConn;
760  int rc;
761 
762  printf("<%s>: server load test thread started.\n", sClientName);
763 
764  //bsServerReqMsgTrace(pClient, (BsVConnHnd_T)BSPROXY_VCONN_SERVER, true);
765 
766  while( true )
767  {
768  // randomly sleep between minimum and maximum times
770 
771  // choose random request to send
772  switch( actions[RandN(uNumActions)] )
773  {
774  case ActionLoopback:
775  sprintf(buf, "%s wants loopback.", sClientName);
776  rc = bsServerReqLoopback(pClient, buf);
777  if( rc == BS_OK )
778  {
779  printf("<%s>: loopback: \"%s\"\n", sClientName, buf);
780  }
781  else
782  {
783  printf("<%s>: loopback: failed: rc=%d\n", sClientName, rc);
784  }
785  break;
786  case ActionSetLogging:
787  if( !OptsFixedDiag )
788  {
789  i = RandN(5);
790  rc = bsServerReqSetLogging(pClient, (int)i);
791  if( rc == BS_OK )
792  {
793  printf("<%s>: setlogging: %d\n", sClientName, (int)i);
794  }
795  else
796  {
797  printf("<%s>: setlogging: failed: rc=%d\n", sClientName, rc);
798  }
799  }
800  break;
801  case ActionGetVersion:
802  rc = bsServerReqGetVersion(pClient, buf, sizeof(buf));
803  if( rc == BS_OK )
804  {
805  printf("<%s>: getversion: \"%s\"\n", sClientName, buf);
806  }
807  else
808  {
809  printf("<%s>: getversion: failed: rc=%d\n", sClientName, rc);
810  }
811  break;
812  case ActionMsgTrace:
813  if( !OptsFixedDiag )
814  {
815  i = RandN(LT_MAX_VCONN+1); // n dev handles/client + 1 server handle
816  if( i == LT_MAX_VCONN )
817  {
818  hndVConn = BSPROXY_VCONN_SERVER;
819  }
820  else
821  {
822  hndVConn = RandVConn(&vconnlist);
823  }
824  if( hndVConn != BSPROXY_VCONN_UNDEF )
825  {
826  j = RandN(2); // do [not] trace
827  rc = bsServerReqMsgTrace(pClient, hndVConn, (bool_t)j);
828  if( rc == BS_OK )
829  {
830  printf("<%s>: msgtrace: vconn=%d, trace=%d\n",
831  sClientName, hndVConn, (int)j);
832  }
833  else
834  {
835  vconnlist.m_uCount = 0;
836  printf("<%s>: msgtrace: failed: rc=%d\n", sClientName, rc);
837  }
838  }
839  }
840  break;
841  case ActionGetVConnList:
842  rc = bsServerReqGetVConnList(pClient, &vconnlist);
843  if( rc == BS_OK )
844  {
845  printf("<%s>: getvconnlist: (%zu)", sClientName, vconnlist.m_uCount);
846  for(i=0; i<vconnlist.m_uCount; ++i)
847  {
848  printf(" %d", vconnlist.m_vecHnd[i]);
849  }
850  printf("\n");
851  }
852  else
853  {
854  vconnlist.m_uCount = 0;
855  printf("<%s>: getvconnlist: failed: rc=%d\n", sClientName, rc);
856  }
857  break;
858  case ActionGetVConnInfo:
859  hndVConn = RandVConn(&vconnlist);
860  if( hndVConn != BSPROXY_VCONN_UNDEF )
861  {
862  rc = bsServerReqGetVConnInfo(pClient, hndVConn, &vconninfo);
863  if( rc == BS_OK )
864  {
865  printf("<%s>: getvconninfo:\n", sClientName);
866  printf(" vconn = %d\n", vconninfo.m_vconn);
867  printf(" rd = %d\n", vconninfo.m_rd);
868  printf(" client = %s\n", vconninfo.m_client);
869  printf(" devuri = %s\n", vconninfo.m_devuri);
870  printf(" moduri = %s\n", vconninfo.m_moduri);
871  printf(" modver = %s\n", vconninfo.m_modver);
872  printf(" moddate = %s\n", vconninfo.m_moddate);
873  }
874  else
875  {
876  vconnlist.m_uCount = 0;
877  printf("<%s>: getvconninfo: failed: rc=%d\n", sClientName, rc);
878  }
879  }
880  break;
881  default:
882  break;
883  }
884  }
885 
886  printf("<%s>: server load test thread terminated.\n", sClientName);
887 
888  return NULL;
889 }
890 
891 /*!
892  * \brief Start server-terminated requests load test thread.
893  *
894  * \param pClient BotSense client.
895  */
897 {
898  pthread_t thread;
899 
900  if( pthread_create(&thread, NULL, LtThreadServer, (void *)pClient) )
901  {
903  "pthread_create(\"server\")");
904  return;
905  }
906 }
907 
908 /*!
909  * \brief Get and pretty print all the versions from all proxied entities.
910  *
911  * The returned BotSense allocatated string is multi-lined.
912  *
913  * \param i Test client instance.
914  */
916 {
917  char buf[256];
918  BsClient_P pClient;
919  int rc;
920 
921  sprintf_s(buf, sizeof(buf), "TestClient%d", i);
922 
923  pClient = bsClientNew(buf);
924 
925  // connect to bsProxy server
926  if( (rc = bsServerConnect(pClient, ProxyIPAddr, ProxyIPPort)) < 0 )
927  {
928  LOGERROR("bsProxy @%s:%d: %s\n", ProxyIPAddr, ProxyIPPort, bsStrError(rc));
929  }
930 
931  // success
932  else
933  {
934  LOGDIAG1("Created client %s.", bsClientAttrGetName(pClient));
935  rc = BS_OK;
936 
938  {
940  }
941  if( ProxiedDevices & LT_DEV_I2C )
942  {
943  ClientStartTestThreadI2C(pClient);
944  }
946  {
947  ClientStartTestThreadNull(pClient);
948  }
950  {
952  }
953  }
954 
955  // Error clean up.
956  if( rc < 0 )
957  {
958  bsClientDelete(pClient);
959  pClient = NULL;
960  }
961 
962  return pClient;
963 }
964 
965 
966 // ...........................................................................
967 // Initialization Functions
968 // ...........................................................................
969 
970 /*!
971  * \brief Convert command-line server option IP address string to
972  * network name/number and port number.
973  *
974  * \par Option Argument Syntax:
975  * proxy: addr[:port]
976  *
977  * \param argv0 Command name.
978  * \param sOptName Option name.
979  * \param optarg Parsed option argument to convert (optional).
980  * \param[out] pOptVal Pointer to converted option value (not used).
981  *
982  * \exception OptsInvalid()
983  *
984  * \return If returns, then returns BS_OK.
985  */
986 static int OptsCvtArgServerAddr(const char *argv0, const char *sOptName,
987  char *optarg, void *pOptVal)
988 {
989  char *sSepField;
990  char *sPort;
991 
992  ProxyIPAddr = NULL;
993  ProxyIPPort = 0;
994 
995  ProxyIPAddr = new_strdup(optarg);
996 
997  sSepField = strchr(ProxyIPAddr, ':');
998 
999  if( sSepField )
1000  {
1001  *sSepField = 0;
1002  sPort = sSepField+1;
1003  ProxyIPPort = (int)atol(sPort);
1004  if( ProxyIPPort <= 0 )
1005  {
1006  OptsInvalid(Argv0, "'%s': Invalid '%s' argument port value.",
1007  optarg, sOptName);
1008  }
1009  }
1010  else
1011  {
1013  }
1014 
1015  if( *ProxyIPAddr == 0 )
1016  {
1017  OptsInvalid(Argv0, "'%s': Invalid '%s' argument address value.",
1018  optarg, sOptName);
1019  }
1020 
1021  return BS_OK;
1022 }
1023 
1024 /*!
1025  * \brief Convert command-line client count option.
1026  *
1027  * \param argv0 Command name.
1028  * \param sOptName Option name.
1029  * \param optarg Parsed option argument to convert (optional).
1030  * \param[out] pOptVal Pointer to converted option value (not used).
1031  *
1032  * \exception OptsInvalid()
1033  *
1034  * \return If returns, then returns BS_OK.
1035  */
1036 static int OptsCvtArgClientCnt(const char *argv0, const char *sOptName,
1037  char *optarg, void *pOptVal)
1038 {
1039  OptsCvtArgInt(argv0, sOptName, optarg, &OptsClientCnt);
1040 
1041  if( (OptsClientCnt < 0) || (OptsClientCnt > LT_MAX_CLIENTS) )
1042  {
1043  OptsInvalid(Argv0, "'%s': Client '%s' argument out-of-range.",
1044  optarg, sOptName);
1045  }
1046 
1047  return BS_OK;
1048 }
1049 
1050 /*!
1051  * \brief Convert command-line devices option string to bitmap.
1052  *
1053  * \par Option Argument Syntax:
1054  * list: dev[,dev...]\n
1055  * behavior: server i2c null serial
1056  *
1057  * \param argv0 Command name.
1058  * \param sOptName Option name.
1059  * \param optarg Parsed option argument to convert (optional).
1060  * \param[out] pOptVal Pointer to converted option value (not used).
1061  *
1062  * \return If returns, then returns BS_OK.
1063  */
1064 static int OptsCvtArgDevices(const char *argv0, const char *sOptName,
1065  char *optarg, void *pOptVal)
1066 {
1067  char *sList; // pointer to list string
1068  char *sDev; // pointer to device string
1069 
1070  ProxiedDevices = 0;
1071 
1072  sList = new_strdup(optarg);
1073 
1074  for(sDev=strtok(sList, ",");
1075  sDev!=NULL;
1076  sDev=strtok(NULL, ","))
1077  {
1078  if( !strcmp(sDev, "server") )
1079  {
1081  }
1082  else if( !strcmp(sDev, "i2c") )
1083  {
1085  }
1086  else if( !strcmp(sDev, "null") )
1087  {
1089  }
1090  else if( !strcmp(sDev, "serial") )
1091  {
1093  }
1094  else
1095  {
1096  OptsInvalid(Argv0, "'%s': Option '%s': Unknown device '%s'.",
1097  optarg, sOptName, sDev);
1098  }
1099  }
1100 
1101  delete(sList);
1102 
1103  return BS_OK;
1104 }
1105 
1106 /*!
1107  * \brief Initialize application.
1108  *
1109  * Any command-line error immediately terminates application.
1110  *
1111  * \param argc Command-line argument count.
1112  * \param argv Command-line argument list.
1113  *
1114  * \return
1115  * Returns \ref APP_EC_OK on success, >0 exit code on failure.
1116  */
1117 static int MainInit(int argc, char *argv[])
1118 {
1119  // Name of this process.
1120  Argv0 = basename(argv[0]);
1121 
1122  //
1123  // Parse input options.
1124  //
1125  argv = OptsGet(Argv0, &PkgInfo, &PgmInfo, OptsInfo, true, &argc, argv);
1126 
1127  RandSeed();
1128 
1129  return APP_EC_OK;
1130 }
1131 
1132 /*!
1133  * \brief Application main.
1134  *
1135  * \param argc Command-line argument count.
1136  * \param argv Command-line argument list.
1137  *
1138  * \par Exit Status:
1139  * Program exits with 0 success, \h_gt 0 on failure.
1140  */
1141 
1142 int main(int argc, char *argv[])
1143 {
1144  int i;
1145 
1146  // Initialize command.
1147  MainInit(argc, argv);
1148 
1149  //
1150  // Create client load tester
1151  //
1152  for(i=0; i<OptsClientCnt; ++i)
1153  {
1154  Client[i] = CreateTestClient(i);
1155  }
1156 
1157  //
1158  // Wait for interrupt.
1159  //
1160  while( true )
1161  {
1162  sleep(5);
1163  }
1164 
1165  //
1166  // Disonnect from server. All opened proxied devices are automatically closed.
1167  // Then delete client, freeing up all resources.
1168  //
1169  for(i=0; i<OptsClientCnt; ++i)
1170  {
1171  bsServerDisconnect(Client[i]);
1172  bsClientDelete(Client[i]);
1173  }
1174 
1175  return APP_EC_OK;
1176 }
static uint_t RandN(uint_t n)
Generate random integer between [0,n).
Definition: bsLoadTest.c:269
#define BS_NULL_DEV_NAME
DevNull device.
Definition: bsNull.h:55
#define LT_MAX_CLIENTS
maximum number of load testing clients
Definition: bsLoadTest.c:89
#define BSPROXY_LISTEN_PORT_DFT
default bsProxy passive socket
Definition: BotSense.h:120
BotSense client application - bsProxy server-terminated core messages.
#define LT_N_CLIENT_DFT
default option load testing client count
Definition: bsLoadTest.c:91
static int OptsCvtArgDevices(const char *argv0, const char *sOptName, char *optarg, void *pOptVal)
Convert command-line devices option string to bitmap.
Definition: bsLoadTest.c:1064
ulong_t seed
the initial seed
Definition: bsLoadTest.c:244
static char * OptsProxyServer
proxy server addr/port
Definition: bsLoadTest.c:107
static char * OptsDevSerial
serial device
Definition: bsLoadTest.c:111
#define LT_DEV_I2C
load test proxied I2C device requests
Definition: bsLoadTest.c:96
static BsClient_P Client[256]
array of clients
Definition: bsLoadTest.c:239
byte_t m_vconn
virtual connection handle
Definition: libBotSense.h:139
static BsVConnHnd_T RandVConn(BsVecHandles_T *pVConnList)
Randomly pick a virtual connection in list.
Definition: bsLoadTest.c:296
#define BSPROXY_VCONN_SERVER
handle for server-terminated msgs
Definition: BotSense.h:140
static int MainInit(int argc, char *argv[])
Initialize application.
Definition: bsLoadTest.c:1117
<b><i>BotSense</i></b> bsProxy client library I2C bus interface.
static char * OptsDevices
number of clients
Definition: bsLoadTest.c:109
#define BSCLIENT_LOG_SYSERROR(pClient, ecode, efmt,...)
Log System Error.
Definition: libBotSense.h:196
static BsClient_P CreateTestClient(int i)
Get and pretty print all the versions from all proxied entities.
Definition: bsLoadTest.c:915
static int OptsCvtArgServerAddr(const char *argv0, const char *sOptName, char *optarg, void *pOptVal)
Convert command-line server option IP address string to network name/number and port number...
Definition: bsLoadTest.c:986
#define BSCLIENT_LOG_ERROR(pClient, ecode, efmt,...)
Log Error.
Definition: libBotSense.h:170
The Client Structure Type.
Definition: bsLibInternal.h:96
ReqGetVConnInfo.
Definition: bsProxyMsgs.h:51
<b><i>BotSense</i></b> bsProxy client library /dev/null interface.
static OptsInfo_T OptsInfo[]
Command-line options information.
Definition: bsLoadTest.c:140
#define BS_OK
not an error, success
Definition: BotSense.h:66
BsVConnHnd_T m_vecHnd[BSPROXY_VCONN_CLIENT_MAX]
vector of handles
Definition: libBotSense.h:125
static void * LtThreadI2C(void *pArg)
Load test proxied I2C device thread.
Definition: bsLoadTest.c:315
static void ClientStartTestThreadI2C(BsClient_P pClient)
Start proxied I2C device load test thread.
Definition: bsLoadTest.c:429
static void ClientStartTestThreadNull(BsClient_P pClient)
Start proxied /dev/null device load test thread.
Definition: bsLoadTest.c:568
static char * Argv0
this command basename
Definition: bsLoadTest.c:106
static int ProxyIPPort
default bsProxy port
Definition: bsLoadTest.c:237
number of message ids
Definition: bsI2CMsgs.h:47
#define BSPROXY_VCONN_UNDEF
undefined virtual connection handle
Definition: BotSense.h:139
static int OptsCvtArgClientCnt(const char *argv0, const char *sOptName, char *optarg, void *pOptVal)
Convert command-line client count option.
Definition: bsLoadTest.c:1036
#define BS_ECODE_NO_EXEC
cannot execute
Definition: BotSense.h:88
<b><i>BotSense</i></b> bsProxy client library RS-232 serial interface.
static void * LtThreadNull(void *pArg)
Load test proxied /dev/null device thread.
Definition: bsLoadTest.c:448
char m_moddate[256]
i/f module date
Definition: libBotSense.h:145
BotSense bsProxy server - client raw I2C NetMsgs XML Definition.
char m_modver[256]
i/f module version
Definition: libBotSense.h:144
<b><i>BotSense</i></b> client library declarations.
#define LT_MAX_VCONN
maximum number of virtual conn. / client
Definition: bsLoadTest.c:90
static union @20 RandomSeq
Random seed.
static void ClientStartTestThreadSerial(BsClient_P pClient)
Start proxied serial device load test thread.
Definition: bsLoadTest.c:714
static const PkgInfo_T PkgInfo
Definition: version.h:45
BotSense bsProxy server - client raw serial NetMsgs XML Definition.
char m_client[256]
client name
Definition: libBotSense.h:141
ReqScan.
Definition: bsI2CMsgs.h:45
#define LT_DEV_SERIAL
load test proxied serial device requests
Definition: bsLoadTest.c:98
size_t m_uCount
vector length
Definition: libBotSense.h:124
ReqGetVConnList.
Definition: bsProxyMsgs.h:49
static void ClientStartTestThreadServer(BsClient_P pClient)
Start server-terminated requests load test thread.
Definition: bsLoadTest.c:896
static char * ProxyIPAddr
default bsProxy IP addr
Definition: bsLoadTest.c:236
char m_moduri[256]
i/f module URI
Definition: libBotSense.h:143
Package version information.
int main(int argc, char *argv[])
Application main.
Definition: bsLoadTest.c:1142
static void * LtThreadServer(void *pArg)
Load test server-terminated messages thread.
Definition: bsLoadTest.c:733
struct _bsClientStruct * BsClient_P
Pointer to client structure forward declaration.
Definition: libBotSense.h:71
static void RandSeed()
Seed random number generator.
Definition: bsLoadTest.c:256
number of message ids
Definition: bsNullMsgs.h:40
static void RandSleep(uint_t tmin, uint_t tmax)
Sleep for a random &mu;s duration between [tmin, tmax].
Definition: bsLoadTest.c:284
#define LT_DEV_NULL
load test proxied /dev/null requests
Definition: bsLoadTest.c:97
static uint_t ProxiedDevices
proxied devices
Definition: bsLoadTest.c:240
static char * OptsDevI2C
i2c device
Definition: bsLoadTest.c:112
#define LT_DEV_SERVER
load test server-terminated requests
Definition: bsLoadTest.c:95
static bool_t OptsFixedDiag
fixed diagnostics
Definition: bsLoadTest.c:110
static OptsPgmInfo_T PgmInfo
Program information.
Definition: bsLoadTest.c:127
int m_rd
resource descriptor
Definition: libBotSense.h:140
#define LT_T_MIN
minimum thread sleep time
Definition: bsLoadTest.c:100
static int OptsClientCnt
number of clients
Definition: bsLoadTest.c:108
#define LT_DEVICES_DFT
default option list of proxied devices
Definition: bsLoadTest.c:93
ushort_t xsubi[3]
successive x_i&#39;th 48-bit value
Definition: bsLoadTest.c:245
#define LT_T_MAX
minimum thread sleep time
Definition: bsLoadTest.c:101
<b><i>BotSense</i></b> package top-level, unifying header declarations.
static void * LtThreadSerial(void *pArg)
Load test proxied serial device thread.
Definition: bsLoadTest.c:587
BotSense bsProxy server - client /dev/null NetMsgs XML Definition.
#define APP_EC_OK
success exit code
Definition: bsLoadTest.c:85
int BsVConnHnd_T
virtual connection handle type
Definition: BotSense.h:151
number of message ids
Definition: bsSerialMsgs.h:44
char m_devuri[256]
device URI
Definition: libBotSense.h:142