blob: bb20f8a7dd20b81adb73b584f46db6ddbbd3e816 [file] [log] [blame]
Benny Prijonoe0312a72005-11-18 00:16:43 +00001/* $Id$ */
Benny Prijonoe7224612005-11-13 19:40:44 +00002/*
Benny Prijonoe0312a72005-11-18 00:16:43 +00003 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
Benny Prijonoe7224612005-11-13 19:40:44 +00004 *
Benny Prijonoe0312a72005-11-18 00:16:43 +00005 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
Benny Prijonoe7224612005-11-13 19:40:44 +00009 *
Benny Prijonoe0312a72005-11-18 00:16:43 +000010 * This program is distributed in the hope that it will be useful,
Benny Prijonoe7224612005-11-13 19:40:44 +000011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Benny Prijonoe0312a72005-11-18 00:16:43 +000012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Benny Prijonoe7224612005-11-13 19:40:44 +000018 */
19#include "test.h"
20#include <pjlib.h>
21#include <pj/compat/high_precision.h>
22
23
24/**
25 * \page page_pjlib_sock_perf_test Test: Socket Performance
26 *
27 * Test the performance of the socket communication. This will perform
28 * simple producer-consumer type of test, where we calculate how long
29 * does it take to send certain number of packets from producer to
30 * consumer.
31 *
32 * This file is <b>pjlib-test/sock_perf.c</b>
33 *
34 * \include pjlib-test/sock_perf.c
35 */
36
37#if INCLUDE_SOCK_PERF_TEST
38
39/*
40 * sock_producer_consumer()
41 *
42 * Simple producer-consumer benchmarking. Send loop number of
43 * buf_size size packets as fast as possible.
44 */
45static int sock_producer_consumer(int sock_type,
46 unsigned buf_size,
47 unsigned loop,
48 unsigned *p_bandwidth)
49{
50 pj_sock_t consumer, producer;
51 pj_pool_t *pool;
52 char *outgoing_buffer, *incoming_buffer;
53 pj_timestamp start, stop;
54 unsigned i;
55 pj_highprec_t elapsed, bandwidth;
56 pj_size_t total_received;
57 pj_status_t rc;
58
59 /* Create pool. */
60 pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
61 if (!pool)
62 return -10;
63
64 /* Create producer-consumer pair. */
65 rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
66 if (rc != PJ_SUCCESS) {
67 app_perror("...error: create socket pair", rc);
68 return -20;
69 }
70
71 /* Create buffers. */
72 outgoing_buffer = pj_pool_alloc(pool, buf_size);
73 incoming_buffer = pj_pool_alloc(pool, buf_size);
74
75 /* Start loop. */
76 pj_get_timestamp(&start);
77 total_received = 0;
78 for (i=0; i<loop; ++i) {
79 pj_ssize_t sent, part_received, received;
80 pj_time_val delay;
81
82 sent = buf_size;
83 rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
84 if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
85 app_perror("...error: send()", rc);
86 return -61;
87 }
88
89 /* Repeat recv() until all data is part_received.
90 * This applies only for non-UDP of course, since for UDP
91 * we would expect all data to be part_received in one packet.
92 */
93 received = 0;
94 do {
95 part_received = buf_size-received;
96 rc = pj_sock_recv(consumer, incoming_buffer+received,
97 &part_received, 0);
98 if (rc != PJ_SUCCESS) {
99 app_perror("...recv error", rc);
100 return -70;
101 }
102 if (part_received <= 0) {
103 PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
104 part_received));
105 return -73;
106 }
107 if ((pj_size_t)part_received != buf_size-received) {
108 if (sock_type != PJ_SOCK_STREAM) {
109 PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
110 buf_size-received, part_received));
111 return -76;
112 }
113 }
114 received += part_received;
115 } while ((pj_size_t)received < buf_size);
116
117 total_received += received;
118
119 /* Stop test if it's been runnign for more than 10 secs. */
120 pj_get_timestamp(&stop);
121 delay = pj_elapsed_time(&start, &stop);
122 if (delay.sec > 10)
123 break;
124 }
125
126 /* Stop timer. */
127 pj_get_timestamp(&stop);
128
129 elapsed = pj_elapsed_usec(&start, &stop);
130
131 /* bandwidth = total_received * 1000 / elapsed */
132 bandwidth = total_received;
133 pj_highprec_mul(bandwidth, 1000);
134 pj_highprec_div(bandwidth, elapsed);
135
136 *p_bandwidth = (pj_uint32_t)bandwidth;
137
138 /* Close sockets. */
139 pj_sock_close(consumer);
140 pj_sock_close(producer);
141
142 /* Done */
143 pj_pool_release(pool);
144
145 return 0;
146}
147
148/*
149 * sock_perf_test()
150 *
151 * Main test entry.
152 */
153int sock_perf_test(void)
154{
155 enum { LOOP = 64 * 1024 };
156 int rc;
157 unsigned bandwidth;
158
159 PJ_LOG(3,("", "...benchmarking socket "
160 "(2 sockets, packet=512, single threaded):"));
161
162 /* Benchmarking UDP */
163 rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth);
164 if (rc != 0) return rc;
165 PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth));
166
167 /* Benchmarking TCP */
168 rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth);
169 if (rc != 0) return rc;
170 PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth));
171
172 return rc;
173}
174
175
176#else
177/* To prevent warning about "translation unit is empty"
178 * when this test is disabled.
179 */
180int dummy_sock_perf_test;
181#endif /* INCLUDE_SOCK_PERF_TEST */
182
183