Home --> Documentations --> PJMEDIA Reference
pjsip-perf is a complete program to measure the performance of PJSIP or other SIP endpoints. It consists of two parts:
- the server, to respond incoming requests, and
- the client, who actively submits requests and measure the performance of the server.
Both server and client part can run simultaneously, to measure the performance when both endpoints are co-located in a single program.
The server accepts both INVITE and non-INVITE requests. The server exports several different types of URL, which would control how the request would be handled by the server:
- URL with "0" as the user part will be handled statelessly. It should not be used with INVITE method.
- URL with "1" as the user part will be handled statefully. If the request is an INVITE request, INVITE transaction will be created and 200/OK response will be sent, along with a valid SDP body. However, the SDP is just a static text body, and is not a proper SDP generated by PJMEDIA.
- URL with "2" as the user part is only meaningful for INVITE requests, as it would be handled call-statefully by the server. For this URL, the server also would generate SDP dynamically and perform a proper SDP negotiation for the incoming call. Also for every call, server will limit the call duration to 10 seconds, on which the call will be terminated if the client doesn't hangup the call.
This file is pjsip-apps/src/samples/pjsip-perf.c
64#include <pjsip_simple.h>
65#include <pjlib-util.h>
69#if (defined(PJ_WIN32) && PJ_WIN32!=0) || (defined(PJ_WIN64) && PJ_WIN64!=0)
73#define THIS_FILE "pjsip-perf.c"
74#define DEFAULT_COUNT (pjsip_cfg()->tsx.max_count/2>10000?10000:pjsip_cfg()->tsx.max_count/2)
75#define JOB_WINDOW 1000
76#define TERMINATE_TSX(x,c)
79#ifndef CACHING_POOL_SIZE
80# define CACHING_POOL_SIZE (256*1024*1024)
91 "o=- 3360842071 3360842071 IN IP4 192.168.0.68\r\n"
93 "c=IN IP4 192.168.0.68\r\n"
95 "m=audio 4000 RTP/AVP 0 8 3 103 102 101\r\n"
96 "a=rtcp:4001 IN IP4 192.168.0.68\r\n"
97 "a=rtpmap:103 speex/16000\r\n"
98 "a=rtpmap:102 speex/8000\r\n"
99 "a=rtpmap:3 GSM/8000\r\n"
100 "a=rtpmap:0 PCMU/8000\r\n"
101 "a=rtpmap:8 PCMA/8000\r\n"
103 "a=rtpmap:101 telephone-event/8000\r\n"
104 "a=fmtp:101 0-15\r\n",
108static pj_str_t mime_application = { "application", 11};
109static pj_str_t mime_sdp = { "sdp", 3};
114 unsigned stateless_cnt;
115 unsigned stateful_cnt;
127 pjsip_endpoint *sip_endpt;
135 unsigned thread_count;
152 unsigned stat_max_window;
156 unsigned total_responses;
157 unsigned response_codes[800];
173 pjsip_inv_session *inv;
178static void app_perror( const char *sender, const char *title,
184 PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
191static pj_bool_t mod_stateless_on_rx_request(pjsip_rx_data *rdata);
195static pjsip_module mod_stateless_server =
198 { "mod-stateless-server", 20 },
200 PJSIP_MOD_PRIORITY_APPLICATION,
205 &mod_stateless_on_rx_request,
213static pj_bool_t mod_stateless_on_rx_request(pjsip_rx_data *rdata)
215 const pj_str_t stateless_user = { "0", 1 };
217 pjsip_sip_uri *sip_uri;
219 uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
222 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
225 sip_uri = (pjsip_sip_uri*) uri;
228 if ( pj_strcmp(&sip_uri->user, &stateless_user)!=0)
236 if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD)
242 pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 200, NULL,
244 app.server.cur_state.stateless_cnt++;
252static pj_bool_t mod_stateful_on_rx_request(pjsip_rx_data *rdata);
256static pjsip_module mod_stateful_server =
259 { "mod-stateful-server", 19 },
261 PJSIP_MOD_PRIORITY_APPLICATION,
266 &mod_stateful_on_rx_request,
274static pj_bool_t mod_stateful_on_rx_request(pjsip_rx_data *rdata)
276 const pj_str_t stateful_user = { "1", 1 };
278 pjsip_sip_uri *sip_uri;
280 uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
283 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
286 sip_uri = (pjsip_sip_uri*) uri;
289 if ( pj_strcmp(&sip_uri->user, &stateful_user)!=0)
296 switch (rdata->msg_info.msg->line.req.method.id) {
297 case PJSIP_INVITE_METHOD:
299 pjsip_msg_body *body;
301 if (dummy_sdp_str. slen == 0)
302 dummy_sdp_str. slen = pj_ansi_strlen(dummy_sdp_str. ptr);
304 body = pjsip_msg_body_create(rdata->tp_info.pool,
305 &mime_application, &mime_sdp,
307 pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
308 200, NULL, NULL, body, NULL);
311 case PJSIP_ACK_METHOD:
314 pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
315 200, NULL, NULL, NULL, NULL);
319 app.server.cur_state.stateful_cnt++;
327static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata);
331static pjsip_module mod_call_server =
334 { "mod-call-server", 15 },
336 PJSIP_MOD_PRIORITY_APPLICATION,
341 &mod_call_on_rx_request,
349static pj_status_t send_response(pjsip_inv_session *inv,
350 pjsip_rx_data *rdata,
354 pjsip_tx_data *tdata;
358 status = pjsip_inv_answer(inv, code, NULL, NULL, &tdata);
360 status = pjsip_inv_initial_answer(inv, rdata, code,
366 status = pjsip_inv_answer(inv, PJSIP_SC_NOT_ACCEPTABLE,
369 status = pjsip_inv_initial_answer(inv, rdata,
370 PJSIP_SC_NOT_ACCEPTABLE,
376 pjsip_inv_send_msg(inv, tdata);
378 pjsip_inv_terminate(inv, 500, PJ_FALSE);
384 status = pjsip_inv_send_msg(inv, tdata);
386 pjsip_tx_data_dec_ref(tdata);
402 send_response( call->inv, NULL, 200, &has_initial);
405static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
407 const pj_str_t call_user = { "2", 1 };
409 pjsip_sip_uri *sip_uri;
413 pjsip_tx_data *tdata;
417 uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
420 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
423 sip_uri = (pjsip_sip_uri*) uri;
426 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
436 if ( pj_strcmp(&sip_uri->user, &call_user) == 0 ||
437 sip_uri->user.slen != 1 ||
438 (*sip_uri->user.ptr != '0' && *sip_uri->user.ptr != '1'))
449 unsigned options = 0;
450 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
451 app.sip_endpt, &tdata);
459 pjsip_response_addr res_addr;
461 pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
462 status = pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata,
464 if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata);
467 pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL,
476 status = pjsip_dlg_create_uas_and_inc_lock( pjsip_ua_instance(), rdata,
477 &app.local_contact, &dlg);
480 pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
492 app.skinfo_cnt, app.skinfo,
499 status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, & call->inv);
501 pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
502 pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
503 pjsip_dlg_dec_lock(dlg);
508 pjsip_dlg_dec_lock(dlg);
511 if (app.server.send_trying) {
512 status = send_response( call->inv, rdata, 100, &has_initial);
518 if (app.server.send_ringing) {
519 status = send_response( call->inv, rdata, 180, &has_initial);
525 if (app.server.delay) {
530 call->ans_timer. cb = &answer_timer_cb;
533 delay. msec = app.server.delay;
536 pjsip_endpt_schedule_timer(app.sip_endpt, & call->ans_timer, &delay);
540 status = send_response( call->inv, rdata, 200, &has_initial);
545 app.server.cur_state.call_cnt++;
556static pj_bool_t mod_responder_on_rx_request(pjsip_rx_data *rdata);
560static pjsip_module mod_responder =
563 { "mod-responder", 13 },
565 PJSIP_MOD_PRIORITY_APPLICATION+1,
570 &mod_responder_on_rx_request,
578static pj_bool_t mod_responder_on_rx_request(pjsip_rx_data *rdata)
580 const pj_str_t reason = pj_str( "Not expecting request at this URI");
585 if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
586 pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, &reason,
601static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata)
603 PJ_LOG(3,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
607 pjsip_rx_data_get_info(rdata),
608 rdata->tp_info.transport->type_name,
609 rdata->pkt_info.src_name,
610 rdata->pkt_info.src_port,
611 ( int)rdata->msg_info.len,
612 rdata->msg_info.msg_buf));
619static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata)
628 PJ_LOG(3,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
631 (tdata->buf.cur - tdata->buf.start),
632 pjsip_tx_data_get_info(tdata),
633 tdata->tp_info.transport->type_name,
634 tdata->tp_info.dst_name,
635 tdata->tp_info.dst_port,
636 ( int)(tdata->buf.cur - tdata->buf.start),
644static pjsip_module msg_logger =
647 { "mod-siprtp-log", 14 },
649 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,
668static pj_bool_t mod_test_on_rx_response(pjsip_rx_data *rdata);
670static void call_on_media_update( pjsip_inv_session *inv,
672static void call_on_state_changed( pjsip_inv_session *inv,
674static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
679static pjsip_module mod_test =
684 PJSIP_MOD_PRIORITY_APPLICATION,
690 &mod_test_on_rx_response,
697static void report_completion( int status_code)
699 app.client.job_finished++;
700 if (status_code >= 200 && status_code < 800)
701 app.client.response_codes[status_code]++;
702 app.client.total_responses++;
708static pj_bool_t mod_test_on_rx_response(pjsip_rx_data *rdata)
710 if (pjsip_rdata_get_tsx(rdata) == NULL) {
711 report_completion(rdata->msg_info.msg->line.status.code);
727 app_perror(THIS_FILE, "Error initializing pjlib", status);
740 app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL);
743 status = pjsip_endpt_create(&app.cp.factory, pj_gethostname()->ptr,
762 pjsip_host_port addrname;
763 const char *transport_type = NULL;
770 if (app.local_addr.slen) {
771 addrname.host = app.local_addr;
772 addrname.port = 5060;
774 if (app.local_port != 0)
775 addrname.port = app.local_port;
778#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
779 } else if (app.use_tcp) {
781 pjsip_tpfactory *tpfactory;
783 transport_type = "tcp";
785 status = pjsip_tcp_transport_start(app.sip_endpt, &local_addr,
786 app.thread_count, &tpfactory);
788 app.local_addr = tpfactory->addr_name.host;
789 app.local_port = tpfactory->addr_name.port;
795 transport_type = "udp";
796 status = pjsip_udp_transport_start(app.sip_endpt, &addr,
797 (app.local_addr.slen ? &addrname:NULL),
798 app.thread_count, &tp);
800 app.local_addr = tp->local_name.host;
801 app.local_port = tp->local_name.port;
806 app_perror(THIS_FILE, "Unable to start transport", status);
811 app.local_uri.slen = pj_ansi_sprintf(app.local_uri.ptr,
812 "<sip:pjsip-perf@%.*s:%d;transport=%s>",
813 ( int)app.local_addr.slen,
818 app.local_contact = app.local_uri;
825 status = pjsip_tsx_layer_init_module(app.sip_endpt);
829 status = pjsip_ua_init_module( app.sip_endpt, NULL );
833 status = pjsip_100rel_init_module(app.sip_endpt);
838 pjsip_inv_callback inv_cb;
842 inv_cb.on_state_changed = &call_on_state_changed;
843 inv_cb.on_new_session = &call_on_forked;
844 inv_cb.on_media_update = &call_on_media_update;
847 status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb);
852 status = pjsip_endpt_register_module( app.sip_endpt, &mod_test);
857 status = pjsip_endpt_register_module( app.sip_endpt, &mod_stateless_server);
861 status = pjsip_endpt_register_module( app.sip_endpt, &mod_responder);
865 status = pjsip_endpt_register_module( app.sip_endpt, &mod_stateful_server);
870 status = pjsip_endpt_register_module( app.sip_endpt, &mod_call_server);
882static void destroy_app()
887 for (i=0; i<app.thread_count; ++i) {
891 app.thread[i] = NULL;
896 pjsip_endpt_destroy(app.sip_endpt);
897 app.sip_endpt = NULL;
903 PJ_LOG(3,(THIS_FILE, "Peak memory size: %uMB",
904 app.cp.peak_used_size / 1000000));
927 pjsip_endpt_get_ioqueue(app.sip_endpt), 0,
937 for (i=0, rtp_port=4000; i< PJ_ARRAY_SIZE(app.skinfo); ++i, rtp_port+=2) {
940 skinfo = &app.skinfo[i];
950 dummy_sdp_str. slen = pj_ansi_strlen(dummy_sdp_str. ptr);
954 app_perror(THIS_FILE, "Error parsing dummy SDP", status);
967static void call_on_media_update( pjsip_inv_session *inv,
971 pjsip_tx_data *tdata;
974 status2 = pjsip_inv_end_session(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE,
977 status2 = pjsip_inv_send_msg(inv, tdata);
985static void call_on_state_changed( pjsip_inv_session *inv,
991 if (inv->mod_data[mod_test.id] != NULL)
995 if (inv->role != PJSIP_UAC_ROLE)
998 if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
999 pjsip_tx_data *tdata;
1005 status = pjsip_inv_end_session(inv, PJSIP_SC_OK, NULL, &tdata);
1007 status = pjsip_inv_send_msg(inv, tdata);
1009 } else if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
1010 report_completion(inv->cause);
1011 inv->mod_data[mod_test.id] = ( void*)( pj_ssize_t)1;
1017static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
1033 pjsip_tx_data *tdata;
1038 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
1056 pjsip_dlg_terminate(dlg);
1060 sdp = app.dummy_sdp;
1063 status = pjsip_inv_create_uac( dlg, sdp, 0, & call->inv);
1065 pjsip_dlg_terminate(dlg);
1074 status = pjsip_inv_invite( call->inv, &tdata);
1082 status = pjsip_inv_send_msg( call->inv, tdata);
1093static pj_status_t verify_sip_url( const char *c_url)
1098 pj_size_t len = (c_url ? pj_ansi_strlen(c_url) : 0);
1100 if (!len) return -1;
1102 pool = pj_pool_create(&app.cp.factory, "check%p", 1024, 0, NULL);
1106 pj_ansi_strcpy(url, c_url);
1109 p = pjsip_parse_uri(pool, url, len, 0);
1110 if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0)
1118static void usage( void)
1122 " pjsip-perf [OPTIONS] -- to start as server\n"
1123 " pjsip-perf [OPTIONS] URL -- to call server (possibly itself)\n"
1126 " URL The SIP URL to be contacted.\n"
1129 " --method=METHOD, -m Set test method (set to INVITE for call benchmark)\n"
1130 " [default: OPTIONS]\n"
1131 " --count=N, -n Set total number of requests to initiate\n"
1133 " --stateless, -s Set to operate in stateless mode\n"
1134 " [default: stateful]\n"
1135 " --timeout=SEC, -t Set client timeout [default=60 sec]\n"
1136 " --window=COUNT, -w Set maximum outstanding job [default: %d]\n"
1138 "SDP options (client and server):\n"
1139 " --real-sdp Generate real SDP from pjmedia, and also perform\n"
1140 " proper SDP negotiation [default: dummy]\n"
1142 "Client and Server options:\n"
1143 " --local-port=PORT, -p Set local port [default: 5060]\n"
1144 " --use-tcp, -T Use TCP instead of UDP. Note that when started as\n"
1145 " client, you must add ;transport=tcp parameter to URL\n"
1147 " --thread-count=N Set number of worker threads [default=1]\n"
1148 " --trying Send 100/Trying response (server, default no)\n"
1149 " --ringing Send 180/Ringing response (server, default no)\n"
1150 " --delay=MS, -d Delay answering call by MS (server, default no)\n"
1153 " --help, -h Display this screen\n"
1154 " --verbose, -v Verbose logging (put more than once for even more)\n"
1156 "When started as server, pjsip-perf can be contacted on the following URIs:\n"
1157 " - sip:0@server-addr To handle requests statelessly.\n"
1158 " - sip:1@server-addr To handle requests statefully.\n"
1159 " - sip:2@server-addr To handle INVITE call.\n",
1160 DEFAULT_COUNT, JOB_WINDOW);
1164static int my_atoi( const char *s)
1171static pj_status_t init_options( int argc, char *argv[])
1173 enum { OPT_THREAD_COUNT = 1, OPT_REAL_SDP, OPT_TRYING, OPT_RINGING };
1175 { "local-port", 1, 0, 'p' },
1176 { "count", 1, 0, 'c' },
1177 { "thread-count", 1, 0, OPT_THREAD_COUNT },
1178 { "method", 1, 0, 'm' },
1179 { "help", 0, 0, 'h' },
1180 { "stateless", 0, 0, 's' },
1181 { "timeout", 1, 0, 't' },
1182 { "real-sdp", 0, 0, OPT_REAL_SDP },
1183 { "verbose", 0, 0, 'v' },
1184 { "use-tcp", 0, 0, 'T' },
1185 { "window", 1, 0, 'w' },
1186 { "delay", 1, 0, 'd' },
1187 { "trying", 0, 0, OPT_TRYING},
1188 { "ringing", 0, 0, OPT_RINGING},
1195 app.local_port = 5060;
1196 app.thread_count = 1;
1197 app.client.job_count = DEFAULT_COUNT;
1198 app.client.method = *pjsip_get_options_method();
1199 app.client.job_window = c = JOB_WINDOW;
1200 app.client.timeout = 60;
1206 while((c=pj_getopt_long(argc,argv, "p:c:m:t:w:d:hsv",
1207 long_options, &option_index))!=-1)
1211 app.local_port = my_atoi(pj_optarg);
1212 if (app.local_port < 0 || app.local_port > 65535) {
1213 PJ_LOG(3,(THIS_FILE, "Invalid --local-port %s", pj_optarg));
1219 app.client.job_count = my_atoi(pj_optarg);
1220 if (app.client.job_count > pjsip_cfg()->tsx.max_count)
1222 "Warning: --count value (%d) exceeds maximum "
1223 "transaction count (%d)", app.client.job_count,
1224 pjsip_cfg()->tsx.max_count));
1227 case OPT_THREAD_COUNT:
1228 app.thread_count = my_atoi(pj_optarg);
1229 if (app.thread_count < 1 || app.thread_count > 16) {
1230 PJ_LOG(3,(THIS_FILE, "Invalid --thread-count %s", pj_optarg));
1238 pjsip_method_init_np(&app.client.method, &temp);
1247 app.client.stateless = PJ_TRUE;
1259 app.client.timeout = my_atoi(pj_optarg);
1260 if (app.client.timeout > 600) {
1261 PJ_LOG(3,(THIS_FILE, "Invalid --timeout %s", pj_optarg));
1267 app.client.job_window = my_atoi(pj_optarg);
1268 if (app.client.job_window <= 0) {
1269 PJ_LOG(3,(THIS_FILE, "Invalid --window %s", pj_optarg));
1279 app.server.delay = my_atoi(pj_optarg);
1280 if (app.server.delay > 3600) {
1281 PJ_LOG(3,(THIS_FILE, "I think --delay %s is too long",
1288 app.server.send_trying = 1;
1292 app.server.send_ringing = 1;
1297 "Invalid argument. Use --help to see help"));
1302 if (pj_optind != argc) {
1304 if (verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) {
1305 PJ_LOG(1,(THIS_FILE, "Invalid SIP URI %s", argv[pj_optind]));
1308 app.client.dst_uri = pj_str(argv[pj_optind]);
1314 if (pj_optind != argc) {
1315 PJ_LOG(1,(THIS_FILE, "Error: unknown options %s", argv[pj_optind]));
1326 pjsip_tx_data *tdata;
1329 status = pjsip_endpt_create_request(app.sip_endpt, &app.client.method,
1330 &app.client.dst_uri, &app.local_uri,
1331 &app.client.dst_uri, &app.local_contact,
1332 NULL, -1, NULL, &tdata);
1334 app_perror(THIS_FILE, "Error creating request", status);
1335 report_completion(701);
1339 status = pjsip_endpt_send_request_stateless(app.sip_endpt, tdata, NULL,
1342 pjsip_tx_data_dec_ref(tdata);
1343 app_perror(THIS_FILE, "Error sending stateless request", status);
1344 report_completion(701);
1353static void tsx_completion_cb( void *token, pjsip_event *event)
1355 pjsip_transaction *tsx;
1359 if (event->type != PJSIP_EVENT_TSX_STATE)
1362 tsx = event->body.tsx_state.tsx;
1364 if (tsx->mod_data[mod_test.id] != NULL) {
1369 if (tsx->state==PJSIP_TSX_STATE_TERMINATED) {
1370 report_completion(tsx->status_code);
1371 tsx->mod_data[mod_test.id] = ( void*)( pj_ssize_t)1;
1373 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
1374 tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
1376 report_completion(tsx->status_code);
1377 tsx->mod_data[mod_test.id] = ( void*)( pj_ssize_t)1;
1379 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
1381 report_completion(tsx->status_code);
1382 tsx->mod_data[mod_test.id] = ( void*)( pj_ssize_t)1;
1384 TERMINATE_TSX(tsx, tsx->status_code);
1392 pjsip_tx_data *tdata;
1395 status = pjsip_endpt_create_request(app.sip_endpt, &app.client.method,
1396 &app.client.dst_uri, &app.local_uri,
1397 &app.client.dst_uri, &app.local_contact,
1398 NULL, -1, NULL, &tdata);
1400 app_perror(THIS_FILE, "Error creating request", status);
1401 report_completion(701);
1405 status = pjsip_endpt_send_request(app.sip_endpt, tdata, -1, NULL,
1406 &tsx_completion_cb);
1408 app_perror(THIS_FILE, "Error sending stateful request", status);
1419static int client_thread( void *arg)
1422 unsigned thread_index = (unsigned)( long)( pj_ssize_t)arg;
1423 unsigned cycle = 0, last_cycle = 0;
1428 end_time. sec += app.client.timeout;
1432 if (app.client.first_request.sec == 0) {
1437 while (app.client.job_submitted < app.client.job_count && !app.thread_quit){
1444 outstanding = app.client.job_submitted - app.client.job_finished;
1447 if (outstanding > ( int)app.client.stat_max_window)
1448 app.client.stat_max_window = outstanding;
1454 for (i=0; outstanding > (int)app.client.job_window && i<1000; ++i) {
1458 pjsip_endpt_handle_events2(app.sip_endpt, &wait, &count);
1459 outstanding = app.client.job_submitted - app.client.job_finished;
1469 if (app.client.method.id == PJSIP_INVITE_METHOD) {
1470 status = make_call(&app.client.dst_uri);
1471 } else if (app.client.stateless) {
1472 status = submit_stateless_job();
1474 status = submit_job();
1478 ++app.client.job_submitted;
1482 pjsip_endpt_handle_events2(app.sip_endpt, &timeout, NULL);
1485 if (cycle - last_cycle >= 500) {
1493 if (thread_index == 0 && now. sec-last_report. sec >= 2) {
1494 printf( "\r%d jobs started, %d completed... ",
1495 app.client.job_submitted, app.client.job_finished);
1502 if (app.client.requests_sent.sec == 0) {
1507 if (thread_index == 0) {
1508 printf( "\r%d jobs started, %d completed%s\n",
1509 app.client.job_submitted, app.client.job_finished,
1510 (app.client.job_submitted!=app.client.job_finished ?
1511 ", waiting..." : ".") );
1518 app.client.job_finished < app.client.job_count &&
1524 for (i=0; i<1000; ++i) {
1527 pjsip_endpt_handle_events2(app.sip_endpt, &timeout, &count);
1544 for (i=0; i<1000; ++i) {
1547 pjsip_endpt_handle_events2(app.sip_endpt, &timeout, &count);
1559static const char *good_number( char *buf, pj_int32_t val)
1562 pj_ansi_sprintf(buf, "%d", val);
1563 } else if (val < 1000000) {
1564 pj_ansi_sprintf(buf, "%d.%dK",
1566 (val % 1000) / 100);
1568 pj_ansi_sprintf(buf, "%d.%02dM",
1570 (val % 1000000) / 10000);
1577static int server_thread( void *arg)
1580 unsigned thread_index = (unsigned)( long)( pj_ssize_t)arg;
1584 next_report = last_report;
1587 while (!app.thread_quit) {
1591 for (i=0; i<100; ++i) {
1593 pjsip_endpt_handle_events2(app.sip_endpt, &timeout, &count);
1598 if (thread_index == 0) {
1604 unsigned stateless, stateful, call;
1605 char str_stateless[32], str_stateful[32], str_call[32];
1612 next_report = last_report;
1615 stateless = app.server.cur_state.stateless_cnt - app.server.prev_state.stateless_cnt;
1616 stateful = app.server.cur_state.stateful_cnt - app.server.prev_state.stateful_cnt;
1617 call = app.server.cur_state.call_cnt - app.server.prev_state.call_cnt;
1619 good_number(str_stateless, app.server.cur_state.stateless_cnt);
1620 good_number(str_stateful, app.server.cur_state.stateful_cnt);
1621 good_number(str_call, app.server.cur_state.call_cnt);
1623 printf( "Total(rate): stateless:%s (%d/s), statefull:%s (%d/s), call:%s (%d/s) \r",
1624 str_stateless, stateless*1000/msec,
1625 str_stateful, stateful*1000/msec,
1626 str_call, call*1000/msec);
1629 app.server.prev_state = app.server.cur_state;
1637static void write_report( const char *msg)
1641#if (defined(PJ_WIN32) && PJ_WIN32!=0) || (defined(PJ_WIN64) && PJ_WIN64!=0)
1642 OutputDebugString(msg);
1643 OutputDebugString( "\n");
1648int main( int argc, char *argv[])
1650 static char report[1024];
1652 printf( "PJSIP Performance Measurement Tool v%s\n"
1653 "(c)2006 pjsip.org\n\n",
1656 if (create_app() != 0)
1659 if (init_options(argc, argv) != 0)
1662 if (init_sip() != 0)
1665 if (init_media() != 0)
1670 if (app.log_level > 4) {
1671 pjsip_endpt_register_module(app.sip_endpt, &msg_logger);
1676 if (app.client.dst_uri.slen != 0) {
1677 if (app.client.method.id == PJSIP_INVITE_METHOD) {
1678 if (app.client.stateless) {
1680 "Info: --stateless option makes no sense for INVITE,"
1689 if (app.client.dst_uri.slen) {
1693 unsigned msec_req, msec_res;
1697 if (app.client.method.id == PJSIP_INVITE_METHOD) {
1698 pj_ansi_strcpy(test_type, "INVITE calls");
1699 } else if (app.client.stateless) {
1700 pj_ansi_sprintf(test_type, "stateless %.*s requests",
1701 ( int)app.client.method.name.slen,
1702 app.client.method.name.ptr);
1704 pj_ansi_sprintf(test_type, "stateful %.*s requests",
1705 ( int)app.client.method.name.slen,
1706 app.client.method.name.ptr);
1710 printf( "Sending %d %s to '%.*s' with %d maximum outstanding jobs, please wait..\n",
1711 app.client.job_count, test_type,
1712 ( int)app.client.dst_uri.slen, app.client.dst_uri.ptr,
1713 app.client.job_window);
1715 for (i=0; i<app.thread_count; ++i) {
1720 app_perror(THIS_FILE, "Unable to create thread", status);
1725 for (i=0; i<app.thread_count; ++i) {
1727 app.thread[i] = NULL;
1730 if (app.client.last_completion.sec) {
1732 duration = app.client.last_completion;
1736 msec_res = app.client.timeout * 1000;
1739 if (msec_res == 0) msec_res = 1;
1741 if (app.client.requests_sent.sec) {
1743 duration = app.client.requests_sent;
1747 msec_req = app.client.timeout * 1000;
1750 if (msec_req == 0) msec_req = 1;
1752 if (app.client.job_submitted < app.client.job_count)
1753 puts( "\ntimed-out!\n");
1758 report, sizeof(report),
1759 "Total %d %s sent in %d ms at rate of %d/sec\n"
1760 "Total %d responses received in %d ms at rate of %d/sec:",
1761 app.client.job_submitted, test_type, msec_req,
1762 app.client.job_submitted * 1000 / msec_req,
1763 app.client.total_responses, msec_res,
1764 app.client.total_responses*1000/msec_res);
1765 write_report(report);
1768 pj_ansi_sprintf(report, "\nDetailed responses received:");
1769 write_report(report);
1771 for (i=0; i< PJ_ARRAY_SIZE(app.client.response_codes); ++i) {
1774 if (app.client.response_codes[i] == 0)
1777 reason = pjsip_get_status_text(i);
1778 pj_ansi_snprintf( report, sizeof(report),
1779 " - %d responses: %7d (%.*s)",
1780 i, app.client.response_codes[i],
1781 ( int)reason-> slen, reason-> ptr);
1782 write_report(report);
1786 pj_ansi_snprintf( report, sizeof(report),
1788 " TOTAL responses: %7d (rate=%d/sec)\n",
1789 app.client.total_responses,
1790 app.client.total_responses*1000/msec_res);
1792 write_report(report);
1794 pj_ansi_sprintf(report, "Maximum outstanding job: %d",
1795 app.client.stat_max_window);
1796 write_report(report);
1801 char s[10], *unused;
1805 puts( "pjsip-perf started in server-mode");
1807 printf( "Receiving requests on the following URIs:\n"
1808 " sip:0@%.*s:%d%s for stateless handling\n"
1809 " sip:1@%.*s:%d%s for stateful handling\n"
1810 " sip:2@%.*s:%d%s for call handling\n",
1811 ( int)app.local_addr.slen,
1814 (app.use_tcp ? ";transport=tcp" : ""),
1815 ( int)app.local_addr.slen,
1818 (app.use_tcp ? ";transport=tcp" : ""),
1819 ( int)app.local_addr.slen,
1822 (app.use_tcp ? ";transport=tcp" : ""));
1823 printf( "INVITE with non-matching user part will be handled call-statefully\n");
1825 for (i=0; i<app.thread_count; ++i) {
1830 app_perror(THIS_FILE, "Unable to create thread", status);
1835 puts( "\nPress <ENTER> to quit\n");
1837 unused = fgets(s, sizeof(s), stdin);
1841 for (i=0; i<app.thread_count; ++i) {
1843 app.thread[i] = NULL;
pj_status_t pjlib_util_init(void)
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt) Definition: endpoint.h:127
pj_status_t pjmedia_endpt_create_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, unsigned stream_cnt, const pjmedia_sock_info sock_info[], pjmedia_sdp_session **p_sdp)
pj_status_t pj_init(void)
unsigned short pj_uint16_t
struct pj_thread_t pj_thread_t
struct pj_timer_heap_t pj_timer_heap_t
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
#define PJ_LOG(level, arg)
void pj_log_set_level(int level)
pj_pool_factory_policy pj_pool_factory_default_policy
void * pj_pool_alloc(pj_pool_t *pool, pj_size_t size)
pj_pool_t * pj_pool_create(pj_pool_factory *factory, const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback)
void * pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
void pj_pool_release(pj_pool_t *pool)
unsigned long pj_strtoul(const pj_str_t *str)
pj_str_t pj_str(char *str)
int pj_stricmp2(const pj_str_t *str1, const char *str2)
int pj_strcmp(const pj_str_t *str1, const pj_str_t *str2)
void pj_bzero(void *dst, pj_size_t size)
pj_uint16_t pj_htons(pj_uint16_t hostshort)
const pj_str_t * pj_gethostname(void)
pj_status_t pj_sockaddr_in_init(pj_sockaddr_in *addr, const pj_str_t *cp, pj_uint16_t port)
pj_status_t pj_thread_destroy(pj_thread_t *thread)
pj_status_t pj_thread_join(pj_thread_t *thread)
pj_status_t pj_thread_create(pj_pool_t *pool, const char *thread_name, pj_thread_proc *proc, void *arg, pj_size_t stack_size, unsigned flags, pj_thread_t **thread)
pj_status_t pj_thread_sleep(unsigned msec)
pj_status_t pj_gettimeofday(pj_time_val *tv)
void pj_time_val_normalize(pj_time_val *t)
#define PJ_TIME_VAL_LT(t1, t2)
#define PJ_TIME_VAL_MSEC(t)
#define PJ_TIME_VAL_SUB(t1, t2)
#define PJ_TIME_VAL_GTE(t1, t2)
#define PJ_ASSERT_ON_FAIL(expr, exec_on_fail)
#define PJ_ASSERT_RETURN(expr, retval)
#define PJ_UNUSED_ARG(arg)
pj_str_t pj_strerror(pj_status_t statcode, char *buf, pj_size_t bufsize)
Definition: pjsip-perf.c:172
pj_timer_heap_callback * cb
Definition: pjsip-perf.c:113
PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.
|