Tools for multicast testing (msend and mreceive) https://github.com/troglobit/mtools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ttcp.c 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /*
  2. * T T C P . C
  3. *
  4. * Test TCP connection. Makes a connection on port 5001
  5. * and transfers fabricated buffers or data copied from stdin.
  6. *
  7. * Usable on 4.2, 4.3, and 4.1a systems by defining one of
  8. * BSD42 BSD43 (BSD41a)
  9. * Machines using System V with BSD sockets should define SYSV.
  10. *
  11. * Modified for operation under 4.2BSD, 18 Dec 84
  12. * T.C. Slattery, USNA
  13. * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
  14. * Modified in 1989 at Silicon Graphics, Inc.
  15. * catch SIGPIPE to be able to print stats when receiver has died
  16. * for tcp, don't look for sentinel during reads to allow small transfers
  17. * increased default buffer size to 8K, nbuf to 2K to transfer 16MB
  18. * moved default port to 5001, beyond IPPORT_USERRESERVED
  19. * make sinkmode default because it is more popular,
  20. * -s now means don't sink/source
  21. * count number of read/write system calls to see effects of
  22. * blocking from full socket buffers
  23. * for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
  24. * buffer alignment options, -A and -O
  25. * print stats in a format that's a bit easier to use with grep & awk
  26. * for SYSV, mimic BSD routines to use most of the existing timing code
  27. *
  28. * Distribution Status -
  29. * Public Domain. Distribution Unlimited.
  30. */
  31. /* Modified by Yvan Pointurier (yp9x), University of Virginia - May 2002 */
  32. /* Modified by Joachim Nilsson (troglobit), GitHub - Jul 2015 */
  33. #define BSD43
  34. /* #define BSD42 */
  35. /* #define BSD41a */
  36. #if defined(sgi)
  37. #define SYSV
  38. #endif
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <signal.h>
  43. #include <ctype.h>
  44. #include <errno.h>
  45. #include <unistd.h>
  46. #include <arpa/inet.h>
  47. #include <sys/types.h>
  48. #include <sys/socket.h>
  49. #include <netinet/in.h>
  50. #include <netinet/tcp.h>
  51. #include <netdb.h>
  52. #include <sys/time.h> /* struct timeval */
  53. #if defined(SYSV)
  54. #include <sys/times.h>
  55. #include <sys/param.h>
  56. struct rusage {
  57. struct timeval ru_utime, ru_stime;
  58. };
  59. #define RUSAGE_SELF 0
  60. #else
  61. #include <sys/resource.h>
  62. #endif
  63. struct sockaddr_in sinme;
  64. struct sockaddr_in sinhim;
  65. struct sockaddr_in frominet;
  66. socklen_t fromlen;
  67. int domain;
  68. int fd; /* fd of network socket */
  69. size_t buflen = 8 * 1024; /* length of buffer */
  70. char *buf; /* ptr to dynamic buffer */
  71. int nbuf = 8 * 1024; /* number of buffers to send in sinkmode */
  72. int bufoffset = 0; /* align buffer to this */
  73. int bufalign = 16 * 1024; /* modulo this */
  74. int udp = 0; /* 0 = tcp, !0 = udp */
  75. int ttl = 100; /* for multicast only */
  76. int options = 0; /* socket options */
  77. int one = 1; /* for 4.3 BSD style setsockopt() */
  78. short port = 5001; /* TCP port number */
  79. char *host; /* ptr to name of host */
  80. int trans; /* 0=receive, !0=transmit mode */
  81. int sinkmode = 1; /* 0=normal I/O, !0=sink/source mode */
  82. int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc
  83. * resource usage. */
  84. int nodelay = 0; /* set TCP_NODELAY socket option */
  85. int b_flag = 0; /* use mread() */
  86. int mcast = 0; /* 1 = multicast reception, 0 = unicast */
  87. char *mgroup; /* multicast group address */
  88. /*#define MAXPAK 32768 *//* max # of packets received */
  89. /*int rcvBytesArray[MAXPAK]; */
  90. /*double rcvTimeArray[MAXPAK]; */
  91. int rcvIndex = 0; /* index in the arrays */
  92. long rate = 0; /* sending rate */
  93. struct hostent *addr;
  94. extern int errno;
  95. char Usage[] = "\
  96. Usage: ttcp -t [-options] host [ < in ]\n\
  97. ttcp -r [-options > out]\n\
  98. Common options:\n\
  99. -l## length of bufs read from or written to network (default 8192)\n\
  100. -u use UDP instead of TCP\n\
  101. -p## port number to send to or listen at (default 5001)\n\
  102. -s -t: don't source a pattern to network, get data from stdin\n\
  103. -r: don't sink (discard), print data on stdout\n\
  104. -A align the start of buffers to this modulus (default 16384)\n\
  105. -O start buffers at this offset from the modulus (default 0)\n\
  106. -v verbose: print more statistics\n\
  107. -d set SO_DEBUG socket option\n\
  108. Options specific to -t:\n\
  109. -n## number of source bufs written to network (default 8192)\n\
  110. -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
  111. -iTTL sets the ttl of the packets (multicast packets)\n\
  112. -R## slows down sending rate (higher values mean slower rates\n\
  113. Options specific to -r:\n\
  114. -B for -s, only output full blocks as specified by -l (for TAR)\n\
  115. -m IP bind to a multicast group designated by its IP address\n\
  116. ";
  117. char stats[128];
  118. size_t nbytes; /* bytes on net */
  119. size_t numCalls; /* # of I/O system calls */
  120. void prep_timer();
  121. double read_timer();
  122. double cput, realt; /* user, real time (seconds) */
  123. static void sigpipe()
  124. {
  125. }
  126. static void err(char *s)
  127. {
  128. fprintf(stderr, "ttcp%s: ", trans ? "-t" : "-r");
  129. perror(s);
  130. fprintf(stderr, "errno=%d\n", errno);
  131. exit(1);
  132. }
  133. static void mes(char *s)
  134. {
  135. fprintf(stderr, "ttcp%s: %s\n", trans ? "-t" : "-r", s);
  136. }
  137. static void pattern(char *cp, size_t cnt)
  138. {
  139. char c = 0;
  140. while (cnt-- > 0) {
  141. while (!isprint((c & 0x7F)))
  142. c++;
  143. *cp++ = (c++ & 0x7F);
  144. }
  145. }
  146. static void tvadd(struct timeval *tsum, struct timeval *t0, struct timeval *t1)
  147. {
  148. tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  149. tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  150. if (tsum->tv_usec > 1000000)
  151. tsum->tv_sec++, tsum->tv_usec -= 1000000;
  152. }
  153. static void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
  154. {
  155. tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  156. tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  157. if (tdiff->tv_usec < 0)
  158. tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  159. }
  160. #define END(x) {while(*x) x++;}
  161. static void psecs(int l, char *cp)
  162. {
  163. int i;
  164. i = l / 3600;
  165. if (i) {
  166. sprintf(cp, "%d:", i);
  167. END(cp);
  168. i = l % 3600;
  169. sprintf(cp, "%d%d", (i / 60) / 10, (i / 60) % 10);
  170. END(cp);
  171. } else {
  172. i = l;
  173. sprintf(cp, "%d", i / 60);
  174. END(cp);
  175. }
  176. i %= 60;
  177. *cp++ = ':';
  178. sprintf(cp, "%d%d", i / 10, i % 10);
  179. }
  180. /*
  181. * M R E A D
  182. *
  183. * This function performs the function of a read(II) but will
  184. * call read(II) multiple times in order to get the requested
  185. * number of characters. This can be necessary because
  186. * network connections don't deliver data with the same
  187. * grouping as it is written with. Written by Robert S. Miles, BRL.
  188. */
  189. static ssize_t mread(int fd, char *bufp, size_t len)
  190. {
  191. int nread;
  192. size_t bytes = 0;
  193. do {
  194. nread = read(fd, bufp, len - bytes);
  195. numCalls++;
  196. if (nread < 0) {
  197. perror("ttcp_mread");
  198. return (-1);
  199. }
  200. if (nread == 0)
  201. return ((int)bytes);
  202. bytes += (unsigned)nread;
  203. bufp += nread;
  204. } while (bytes < len);
  205. return bytes;
  206. }
  207. /*
  208. * N R E A D
  209. */
  210. static ssize_t Nread(int fd, char *buf, size_t len)
  211. {
  212. size_t bytes;
  213. struct sockaddr_in from;
  214. socklen_t from_len = sizeof(from);
  215. if (udp) {
  216. bytes = recvfrom(fd, buf, len, 0, (struct sockaddr *)&from, &from_len);
  217. numCalls++;
  218. } else {
  219. if (b_flag)
  220. bytes = mread(fd, buf, len); /* fill buf */
  221. else {
  222. bytes = read(fd, buf, len);
  223. numCalls++;
  224. }
  225. }
  226. return bytes;
  227. }
  228. static void delay(int us)
  229. {
  230. struct timeval tv;
  231. tv.tv_sec = 0;
  232. tv.tv_usec = us;
  233. select(1, NULL, NULL, NULL, &tv);
  234. }
  235. /*
  236. * N W R I T E
  237. */
  238. static ssize_t Nwrite(int fd, char *buf, size_t len)
  239. {
  240. int i;
  241. ssize_t bytes;
  242. if (rate > 0)
  243. for (i = 0; i < rate * 100; i++) ;
  244. if (udp) {
  245. again:
  246. bytes = sendto(fd, buf, len, 0, (struct sockaddr *)&sinhim, sizeof(sinhim));
  247. numCalls++;
  248. if (bytes < 0 && errno == ENOBUFS) {
  249. delay(18000);
  250. errno = 0;
  251. goto again;
  252. }
  253. } else {
  254. bytes = write(fd, buf, len);
  255. numCalls++;
  256. }
  257. return bytes;
  258. }
  259. int main(int argc, char *argv[])
  260. {
  261. unsigned long addr_tmp;
  262. if (argc < 2)
  263. goto usage;
  264. argv++;
  265. argc--;
  266. while (argc > 0 && argv[0][0] == '-') {
  267. switch (argv[0][1]) {
  268. case 'B':
  269. b_flag = 1;
  270. break;
  271. case 't':
  272. trans = 1;
  273. break;
  274. case 'r':
  275. trans = 0;
  276. break;
  277. case 'd':
  278. options |= SO_DEBUG;
  279. break;
  280. case 'D':
  281. nodelay = 1;
  282. break;
  283. case 'n':
  284. nbuf = atoi(&argv[0][2]);
  285. break;
  286. case 'l':
  287. buflen = atoi(&argv[0][2]);
  288. break;
  289. case 's':
  290. sinkmode = 0; /* sink/source data */
  291. break;
  292. case 'p':
  293. port = atoi(&argv[0][2]);
  294. break;
  295. case 'u':
  296. udp = 1;
  297. break;
  298. case 'v':
  299. verbose = 1;
  300. break;
  301. case 'A':
  302. bufalign = atoi(&argv[0][2]);
  303. break;
  304. case 'O':
  305. bufoffset = atoi(&argv[0][2]);
  306. break;
  307. case 'i':
  308. ttl = atoi(&argv[0][2]);
  309. break;
  310. case 'R':
  311. rate = atol(&argv[0][2]);
  312. break;
  313. case 'm':
  314. mcast = 1;
  315. argv++;
  316. argc--;
  317. if (argc > 0)
  318. mgroup = argv[0];
  319. else
  320. goto usage;
  321. break;
  322. default:
  323. goto usage;
  324. }
  325. argv++;
  326. argc--;
  327. }
  328. if (trans) {
  329. /* xmitr */
  330. if (argc != 1)
  331. goto usage;
  332. memset(&sinhim, 0, sizeof(sinhim));
  333. host = argv[0];
  334. if (atoi(host) > 0) {
  335. /* Numeric */
  336. sinhim.sin_family = AF_INET;
  337. #if defined(cray)
  338. addr_tmp = inet_addr(host);
  339. sinhim.sin_addr = addr_tmp;
  340. #else
  341. sinhim.sin_addr.s_addr = inet_addr(host);
  342. #endif
  343. } else {
  344. if ((addr = gethostbyname(host)) == NULL)
  345. err("bad hostname");
  346. sinhim.sin_family = addr->h_addrtype;
  347. memcpy(&addr_tmp, addr->h_addr, addr->h_length);
  348. #if defined(cray)
  349. sinhim.sin_addr = addr_tmp;
  350. #else
  351. sinhim.sin_addr.s_addr = addr_tmp;
  352. #endif /* cray */
  353. }
  354. sinhim.sin_port = htons(port);
  355. sinme.sin_port = 0; /* free choice */
  356. } else {
  357. /* rcvr */
  358. sinme.sin_port = htons(port);
  359. }
  360. if (udp && buflen < 5) {
  361. buflen = 5; /* send more than the sentinel size */
  362. }
  363. buf = (char *)malloc(buflen + bufalign);
  364. if (!buf)
  365. err("malloc");
  366. if (bufalign != 0)
  367. buf += (bufalign - ((int)buf % bufalign) + bufoffset) % bufalign;
  368. if (trans) {
  369. fprintf(stdout,
  370. "#ttcp-t: buflen=%zd, nbuf=%d, align=%d/+%d, port=%d %s -> %s\n",
  371. buflen, nbuf, bufalign, bufoffset, port, udp ? "udp" : "tcp", argv[0]);
  372. } else {
  373. fprintf(stdout,
  374. "#ttcp-r: buflen=%zd, nbuf=%d, align=%d/+%d, port=%d %s\n",
  375. buflen, nbuf, bufalign, bufoffset, port, udp ? "udp" : "tcp");
  376. }
  377. if ((fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
  378. err("socket");
  379. mes("socket");
  380. if (bind(fd, (struct sockaddr *)&sinme, sizeof(sinme)) < 0)
  381. err("bind");
  382. if (mcast) {
  383. struct ip_mreq stMreq;
  384. stMreq.imr_multiaddr.s_addr = inet_addr(mgroup);
  385. stMreq.imr_interface.s_addr = INADDR_ANY;
  386. if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0)
  387. err("multicast group join");
  388. else
  389. fprintf(stdout, "#Joined group %s\n", mgroup);
  390. }
  391. if (!udp) {
  392. signal(SIGPIPE, sigpipe);
  393. if (trans) {
  394. /* We are the client if transmitting */
  395. if (options) {
  396. #if defined(BSD42)
  397. if (setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  398. #else /* BSD43 */
  399. if (setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  400. #endif
  401. err("setsockopt");
  402. }
  403. if (nodelay) {
  404. struct protoent *p;
  405. p = getprotobyname("tcp");
  406. if (p && setsockopt(fd, p->p_proto, TCP_NODELAY, &one, sizeof(one)) < 0)
  407. err("setsockopt: nodelay");
  408. mes("nodelay");
  409. }
  410. if (connect(fd, (struct sockaddr *)&sinhim, sizeof(sinhim)) < 0)
  411. err("connect");
  412. mes("connect");
  413. } else {
  414. /* otherwise, we are the server and
  415. * should listen for the connections
  416. */
  417. listen(fd, 0); /* allow a queue of 0 */
  418. if (options) {
  419. #if defined(BSD42)
  420. if (setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  421. #else /* BSD43 */
  422. if (setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  423. #endif
  424. err("setsockopt");
  425. }
  426. fromlen = sizeof(frominet);
  427. domain = AF_INET;
  428. if ((fd = accept(fd, (struct sockaddr *)&frominet, &fromlen)) < 0) {
  429. err("accept");
  430. } else {
  431. struct sockaddr_in peer;
  432. socklen_t peerlen = sizeof(peer);
  433. if (getpeername(fd, (struct sockaddr *)&peer, &peerlen) < 0)
  434. err("getpeername");
  435. fprintf(stderr, "ttcp-r: accept from %s\n", inet_ntoa(peer.sin_addr));
  436. }
  437. }
  438. }
  439. prep_timer();
  440. errno = 0;
  441. if (sinkmode) {
  442. ssize_t cnt;
  443. if (udp) {
  444. int ret = 0;
  445. if ((ntohl(sinhim.sin_addr.s_addr)) >> 28 == 0xe) {
  446. ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(int));
  447. if (ret == -1)
  448. fprintf(stderr, "Error while setting TTL\n");
  449. else
  450. fprintf(stdout, "#TTL set to %d\n", ttl);
  451. }
  452. }
  453. if (trans) {
  454. pattern(buf, buflen);
  455. if (udp)
  456. Nwrite(fd, buf, 4); /* rcvr start */
  457. while (nbuf-- && Nwrite(fd, buf, buflen) == (ssize_t)buflen)
  458. nbytes += buflen;
  459. if (udp)
  460. Nwrite(fd, buf, 4); /* rcvr end */
  461. } else {
  462. if (udp) {
  463. while ((cnt = Nread(fd, buf, buflen)) > 0) {
  464. /*
  465. //yp9x: allow for duplicate starting packet
  466. static int going = 2;
  467. if( cnt <= 4 ) {
  468. if( going == 0)
  469. break;
  470. going--;
  471. prep_timer();
  472. */
  473. /*
  474. //original version
  475. static int going = 0;
  476. if( cnt <= 4 ) {
  477. if( going )
  478. break;
  479. going=1;
  480. prep_timer();
  481. */
  482. static int going = 0;
  483. if (cnt <= 4) {
  484. if (going)
  485. break;
  486. going = 1;
  487. prep_timer();
  488. } else {
  489. nbytes += cnt;
  490. read_timer(stats, sizeof(stats));
  491. // fprintf(stdout, "%f\t%d\n", realt, nbytes);
  492. rcvIndex++;
  493. }
  494. }
  495. } else {
  496. while ((cnt = Nread(fd, buf, buflen)) > 0) {
  497. nbytes += cnt;
  498. }
  499. }
  500. }
  501. } else {
  502. ssize_t cnt;
  503. if (trans) {
  504. while ((cnt = read(0, buf, buflen)) > 0 && Nwrite(fd, buf, cnt) == cnt)
  505. nbytes += cnt;
  506. } else {
  507. while ((cnt = Nread(fd, buf, buflen)) > 0 && write(1, buf, cnt) == cnt)
  508. nbytes += cnt;
  509. }
  510. }
  511. if (errno)
  512. err("IO");
  513. read_timer(stats, sizeof(stats));
  514. if (udp && trans) {
  515. Nwrite(fd, buf, 4); /* rcvr end */
  516. Nwrite(fd, buf, 4); /* rcvr end */
  517. Nwrite(fd, buf, 4); /* rcvr end */
  518. Nwrite(fd, buf, 4); /* rcvr end */
  519. Nwrite(fd, buf, 4); /* rcvr end *//* yp9x */
  520. Nwrite(fd, buf, 4); /* rcvr end *//* yp9x */
  521. Nwrite(fd, buf, 4); /* rcvr end *//* yp9x */
  522. Nwrite(fd, buf, 4); /* rcvr end *//* yp9x */
  523. }
  524. if (cput <= 0.0)
  525. cput = 0.001;
  526. if (realt <= 0.0)
  527. realt = 0.001;
  528. fprintf(stdout, "#ttcp%s: %ld bytes in %.2f real seconds = %.2f KB/sec +++\n",
  529. trans ? "-t" : "-r", nbytes, realt, ((double)nbytes) / realt / 1024);
  530. if (verbose) {
  531. fprintf(stdout,
  532. "#ttcp%s: %ld bytes in %.2f CPU seconds = %.2f KB/cpu sec\n",
  533. trans ? "-t" : "-r", nbytes, cput, ((double)nbytes) / cput / 1024);
  534. }
  535. fprintf(stdout, "#ttcp%s: %zd I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
  536. trans ? "-t" : "-r", numCalls, 1024.0 * realt / ((double)numCalls), ((double)numCalls) / realt);
  537. fprintf(stdout, "#ttcp%s: %s\n", trans ? "-t" : "-r", stats);
  538. if (verbose) {
  539. fprintf(stdout, "#ttcp%s: buffer address %p\n", trans ? "-t" : "-r", buf);
  540. }
  541. /* printStats(); */
  542. exit(0);
  543. usage:
  544. fprintf(stderr, "%s", Usage);
  545. exit(1);
  546. }
  547. static struct timeval time0; /* Time at which timing started */
  548. static struct rusage ru0; /* Resource utilization at the start */
  549. static void prusage();
  550. static void tvadd();
  551. static void tvsub();
  552. static void psecs();
  553. #if defined(SYSV)
  554. /*ARGSUSED*/ static getrusage(ignored, ru)
  555. int ignored;
  556. struct rusage *ru;
  557. {
  558. struct tms buf;
  559. times(&buf);
  560. /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
  561. ru->ru_stime.tv_sec = buf.tms_stime / HZ;
  562. ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
  563. ru->ru_utime.tv_sec = buf.tms_utime / HZ;
  564. ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
  565. }
  566. #if !defined(sgi)
  567. /*ARGSUSED*/ static gettimeofday(tp, zp)
  568. struct timeval *tp;
  569. struct timezone *zp;
  570. {
  571. tp->tv_sec = time(0);
  572. tp->tv_usec = 0;
  573. }
  574. #endif
  575. #endif /* SYSV */
  576. /*
  577. * P R E P _ T I M E R
  578. */
  579. void prep_timer(void)
  580. {
  581. gettimeofday(&time0, (struct timezone *)0);
  582. getrusage(RUSAGE_SELF, &ru0);
  583. }
  584. /*
  585. * R E A D _ T I M E R
  586. *
  587. */
  588. double read_timer(char *str, int len)
  589. {
  590. struct timeval timedol;
  591. struct rusage ru1;
  592. struct timeval td;
  593. struct timeval tend, tstart;
  594. char line[132];
  595. getrusage(RUSAGE_SELF, &ru1);
  596. gettimeofday(&timedol, (struct timezone *)0);
  597. prusage(&ru0, &ru1, &timedol, &time0, line);
  598. strncpy(str, line, len);
  599. /* Get real time */
  600. tvsub(&td, &timedol, &time0);
  601. realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
  602. /* Get CPU time (user+sys) */
  603. tvadd(&tend, &ru1.ru_utime, &ru1.ru_stime);
  604. tvadd(&tstart, &ru0.ru_utime, &ru0.ru_stime);
  605. tvsub(&td, &tend, &tstart);
  606. cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
  607. if (cput < 0.00001)
  608. cput = 0.00001;
  609. return (cput);
  610. }
  611. static void prusage(struct rusage *r0, struct rusage *r1, struct timeval *e, struct timeval *b, char *outp)
  612. {
  613. struct timeval tdiff;
  614. time_t t;
  615. char *cp;
  616. int i;
  617. int ms;
  618. t = (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
  619. (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
  620. (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 + (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
  621. ms = (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000;
  622. #if defined(SYSV)
  623. cp = "%Uuser %Ssys %Ereal %P";
  624. #else
  625. cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
  626. #endif
  627. for (; *cp; cp++) {
  628. if (*cp != '%')
  629. *outp++ = *cp;
  630. else if (cp[1])
  631. switch (*++cp) {
  632. case 'U':
  633. tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
  634. sprintf(outp, "%d.%01d", (int)tdiff.tv_sec, (int)tdiff.tv_usec / 100000);
  635. END(outp);
  636. break;
  637. case 'S':
  638. tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
  639. sprintf(outp, "%d.%01d", (int)tdiff.tv_sec, (int)tdiff.tv_usec / 100000);
  640. END(outp);
  641. break;
  642. case 'E':
  643. psecs(ms / 100, outp);
  644. END(outp);
  645. break;
  646. case 'P':
  647. sprintf(outp, "%d%%", (int)(t * 100 / ((ms ? ms : 1))));
  648. END(outp);
  649. break;
  650. #if !defined(SYSV)
  651. case 'W':
  652. i = r1->ru_nswap - r0->ru_nswap;
  653. sprintf(outp, "%d", i);
  654. END(outp);
  655. break;
  656. case 'X':
  657. sprintf(outp, "%d", t == 0 ? 0 : (int)((r1->ru_ixrss - r0->ru_ixrss) / t));
  658. END(outp);
  659. break;
  660. case 'D':
  661. sprintf(outp, "%d", t == 0 ? 0 : (int)((r1->ru_idrss + r1->ru_isrss - (r0->ru_idrss + r0->ru_isrss)) / t));
  662. END(outp);
  663. break;
  664. case 'K':
  665. sprintf(outp, "%d", t == 0 ? 0 : (int)(
  666. ((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) -
  667. (r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t));
  668. END(outp);
  669. break;
  670. case 'M':
  671. sprintf(outp, "%d", (int)(r1->ru_maxrss / 2));
  672. END(outp);
  673. break;
  674. case 'F':
  675. sprintf(outp, "%d", (int)(r1->ru_majflt - r0->ru_majflt));
  676. END(outp);
  677. break;
  678. case 'R':
  679. sprintf(outp, "%d", (int)(r1->ru_minflt - r0->ru_minflt));
  680. END(outp);
  681. break;
  682. case 'I':
  683. sprintf(outp, "%d", (int)(r1->ru_inblock - r0->ru_inblock));
  684. END(outp);
  685. break;
  686. case 'O':
  687. sprintf(outp, "%d", (int)(r1->ru_oublock - r0->ru_oublock));
  688. END(outp);
  689. break;
  690. case 'C':
  691. sprintf(outp, "%d+%d", (int)(r1->ru_nvcsw - r0->ru_nvcsw),
  692. (int)(r1->ru_nivcsw - r0->ru_nivcsw));
  693. END(outp);
  694. break;
  695. #endif /* !SYSV */
  696. }
  697. }
  698. *outp = '\0';
  699. }
  700. /**
  701. * Local Variables:
  702. * version-control: t
  703. * indent-tabs-mode: t
  704. * c-file-style: "linux"
  705. * End:
  706. */